我正在尝试使用nodatime解释从第三方API检索的日期。日期以相同的响应方式以令人讨厌的格式出现,我特别有麻烦的是:
:{
"ShortDate": "2017-01-01",
"LongDate": "01 January 2017"
}
我可以使用nodapatternconverter正确地对一种格式或另一种格式,但不能同时进行。
一个简单的示例显示问题是这样的:
using Newtonsoft.Json;
using NodaTime;
using NodaTime.Serialization.JsonNet;
using NodaTime.Text;
namespace NodaLocalDateConverterTest
{
class ExampleDatedModel
{
public LocalDate ShortDate { get; set; }
public LocalDate LongDate { get; set; }
}
class Program
{
static void Main(string[] args)
{
var exampleJsonString =
@"{
""ShortDate"": ""2017-01-01"",
""LongDate"": ""01 January 2017""
}";
var serialisationSettings = new JsonSerializerSettings();
//NodaTime default converter supports ShortDate format
serialisationSettings.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
//Exception on LongDate property
var deserialisedExample1 = JsonConvert.DeserializeObject<ExampleDatedModel>(exampleJsonString, serialisationSettings);
serialisationSettings.Converters.Remove(NodaConverters.LocalDateConverter);
serialisationSettings.Converters.Add(new NodaPatternConverter<LocalDate>(LocalDatePattern.CreateWithInvariantCulture("dd MMMM yyyy")));
//Exception on ShortDate property
var deserialisedExample2 = JsonConvert.DeserializeObject<ExampleDatedModel>(exampleJsonString, serialisationSettings);
}
}
}
使用默认串行器给出了长期属性的异常:
类型的未经手的例外 'Nodatime.text.unparsableValueException'发生在 newtonsoft.json.dll
附加信息:值字符串与所需的不匹配 格式字符串" yyyy"的编号。分析价值:'^1月1日 2017'。(^表示错误位置。)
用自定义模式转换器替换在Shortdate属性上抛出异常:
类型的未经手的例外 'Nodatime.text.unparsableValueException'发生在 newtonsoft.json.dll
附加信息:值字符串与简单的 格式字符串的字符"。解析值:'20^17-01-01'。 (^表示错误位置。)
原则上,我认为我可以使用两个不同的转换器作为两个属性,例如
class ExampleDatedModel
{
[JsonConverter(typeof(ShortDateConverter)]
public LocalDate ShortDate { get; set; }
[JsonConverter(typeof(LongDateConverter)]
public LocalDate LongDate { get; set; }
}
但是,我看不到如何将Nodatime的NodaPatternConverter与属性一起使用,因为您无法使用模式实例化转换器。
该文档对"可以使用NodaPatternConverter轻松创建自定义转换器"。但没有任何例子!
我可能的解决方案是
- 创建一对源自NodapatternConverter的转换器,该转换器是为两个模式配置的。
- nodapatternconverter已密封,因此不能继承。
- 创建一对源自jsonconverter的转换器来处理这两种模式
- 我想这些会在内部使用不同模式的两个版本。
- 整个JSONCONVERTER的重新实现似乎过高。
- 当字符串随后转换日期时,
- 可以将日期审理。
- 需要为具有多种类型的每个类实施。
- 使通用方法从API获取资源更复杂。
,但我希望我只是错过了一种标记使用现有转换器的资源类别的方法。
这确实是我们未考虑的用例。对于"正常"使用情况,密封NodaPatternConverter
感觉就像是正确的方法 - 但是,当必须通过 type 而不是实例化指定JsonConverter
时,密封件令人沮丧。我已经提出了一个问题,以在2.0中解决此问题,希望下个月左右发布。(现在已实施 - 拉请请求也显示了示例使用量。)
但是,与此同时,我可能 fork NodaPatternConverter
-添加评论说它只有在那里,直到您可以使用2.0。
您可能需要对其进行修剪一下,因为您可能不需要额外的验证,假设您控制所有将要序列化数据的代码 - 如果您不必担心非ISO LocalDate
值,您可能不需要验证。
另一个方面是,如果您只使用转换器来解析,您根本就不需要写作方面 - 目前您可能会派出一个例外。
启用NodaPatternConverter
的替代方法是具有简单的(抽象)DelegatingConverterBase
类型,该类型将其委派给另一个JsonConverter
。典型的用法将是:
public sealed class ShortDateConverter : DelegatingConverterBase
{
public ShortDateConverter() : base(NodaConverters.LocalDate) {}
}
这可能是更优雅的关注点 - 并且可以用更少的代码来实现,直到它也是NODA时间的一部分:
public abstract class DelegatingConverterBase : JsonConverter
{
private readonly JsonConverter original;
protected DelegatingConverterBase(JsonConverter original)
{
this.original = original;
}
public override void WriteJson(
JsonWriter writer, object value, JsonSerializer serializer) =>
original.WriteJson(writer, value, serializer);
public override object ReadJson(
JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) =>
original.ReadJson(reader, objectType, existingValue, serializer);
public override bool CanRead => original.CanRead;
public override bool CanWrite => original.CanWrite;
public override bool CanConvert(Type objectType) => original.CanConvert(objectType);
}