JSON.NET 不会正确反序列化 class
JSON.NET won't deserialize class correctly
我正在尝试使 class(包含 NodaTime
的 ZonedDateTime
属性)正确反序列化(使用 JSON.NET),但它没有似乎有效。
我也在引用和使用NodaTime.Serialization.JsonNet
。
序列化顺利,结果 JSON 正确,但反序列化生成错误的 ZonedDateTime
值。
在使用 NodaTime.Serialization.JsonNet
之前,我为 JSON.NET 编写了自己的自定义序列化程序,但我遇到了同样的问题。我注意到,我的自定义 JsonConverter
的 ReadJson()
方法正在生成正确的反序列化 ZonedDateTime
值,但是当 class 的构造函数托管 [=调用了 14=] 属性,ZonedDateTime
属性的输入值错误。
代码如下:
class Program
{
static void Main(string[] args)
{
var obj = new ZonedTimeDetails(ZonedDateTime.FromDateTimeOffset(DateTime.Now), ZonedDateTime.FromDateTimeOffset(DateTime.Now.AddHours(1)), false);
var json = JsonConvert.SerializeObject(obj, new FullJsonSerializerSettings());
var obj2 = JsonConvert.DeserializeObject<ZonedTimeDetails>(json, new FullJsonSerializerSettings());
return;
}
}
public class FullJsonSerializerSettings : JsonSerializerSettings
{
public FullJsonSerializerSettings()
{
ContractResolver = new AcTypeContractResolver((MemberInfo memberInfo) => {
if (memberInfo is PropertyInfo pi)
{
var methodInfo = pi.GetSetMethod(true);
if (methodInfo == null)
{
return o => false;
}
}
return o => true;
});
TypeNameHandling = TypeNameHandling.All;
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full;
Converters.Add(NodaConverters.CreateZonedDateTimeConverter(DateTimeZoneProviders.Serialization));
}
}
public class AcTypeContractResolver : DefaultContractResolver
{
private readonly Predicate<object> _predicate;
private readonly Func<MemberInfo, Predicate<object>> _predicateFactory;
public AcTypeContractResolver(Predicate<object> predicate)
{
_predicate = predicate;
}
public AcTypeContractResolver(Func<MemberInfo, Predicate<object>> predicateFactory)
{
_predicateFactory = predicateFactory;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
property.Ignored = false;
property.ShouldSerialize = _predicate ?? _predicateFactory?.Invoke(member);
property.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
return property;
}
}
public class ZonedTimeDetails
{
[JsonConstructor]
public ZonedTimeDetails(ZonedDateTime zoneStart, ZonedDateTime zoneEnd, bool isOverflow = false)
{
ZonedStart = zoneStart;
ZonedEnd = zoneEnd;
IsOverflow = isOverflow;
}
public ZonedDateTime ZonedStart { get; private set; }
public ZonedDateTime ZonedEnd { get; private set; }
public bool IsOverflow { get; private set; }
public DateTime Start => ZonedStart.ToDateTimeUnspecified();
public DateTime End => ZonedEnd.ToDateTimeUnspecified();
public double DurationMin => (ZonedEnd - ZonedStart).TotalMinutes;
}
这是整个项目,如果对您有帮助的话:
https://mega.nz/#!hFc0RAbS!teJ3Y4JHqCx1aHxUVU4kUFs30xwTTyF6QTpRB0D1Fnw
如果有人知道出了什么问题,请告诉我。
据我所知,问题出在 ZonedTimeDetails
class,但我相信这应该有效。 class 的 属性 名称与 ctor 参数名称相匹配,所以我不明白为什么我在反序列化过程中得到错误的值。
更新:
如果我为 ZonedDateTime
属性 public 创建设置器,它可以工作,但我需要 class 是不可变的。根据 SO (1, 2) 上的其他答案,此构造函数注入应该有效。
除此之外,在我使用 ZonedDateTime
之前,我在那个 class 中使用了 DateTime
属性。使用 setter private 一切正常。
问题是 ZonedTimeDetails
构造函数中的参数名称与 JSON 不匹配,后者是通过序列化同一个 class 创建的。 属性 名称有一个 d
(例如 ZonedStart
),而构造函数 属性 名称没有(zoneStart
)。因此,当调用构造函数时,会将空结构传递给这些参数。
要修复,只需更改构造函数参数名称以匹配 属性 名称:
[JsonConstructor]
public ZonedTimeDetails(ZonedDateTime zonedStart, ZonedDateTime zonedEnd, bool isOverflow = false)
{
ZonedStart = zonedStart;
ZonedEnd = zonedEnd;
IsOverflow = isOverflow;
}
我正在尝试使 class(包含 NodaTime
的 ZonedDateTime
属性)正确反序列化(使用 JSON.NET),但它没有似乎有效。
我也在引用和使用NodaTime.Serialization.JsonNet
。
序列化顺利,结果 JSON 正确,但反序列化生成错误的 ZonedDateTime
值。
在使用 NodaTime.Serialization.JsonNet
之前,我为 JSON.NET 编写了自己的自定义序列化程序,但我遇到了同样的问题。我注意到,我的自定义 JsonConverter
的 ReadJson()
方法正在生成正确的反序列化 ZonedDateTime
值,但是当 class 的构造函数托管 [=调用了 14=] 属性,ZonedDateTime
属性的输入值错误。
代码如下:
class Program
{
static void Main(string[] args)
{
var obj = new ZonedTimeDetails(ZonedDateTime.FromDateTimeOffset(DateTime.Now), ZonedDateTime.FromDateTimeOffset(DateTime.Now.AddHours(1)), false);
var json = JsonConvert.SerializeObject(obj, new FullJsonSerializerSettings());
var obj2 = JsonConvert.DeserializeObject<ZonedTimeDetails>(json, new FullJsonSerializerSettings());
return;
}
}
public class FullJsonSerializerSettings : JsonSerializerSettings
{
public FullJsonSerializerSettings()
{
ContractResolver = new AcTypeContractResolver((MemberInfo memberInfo) => {
if (memberInfo is PropertyInfo pi)
{
var methodInfo = pi.GetSetMethod(true);
if (methodInfo == null)
{
return o => false;
}
}
return o => true;
});
TypeNameHandling = TypeNameHandling.All;
TypeNameAssemblyFormat = FormatterAssemblyStyle.Full;
Converters.Add(NodaConverters.CreateZonedDateTimeConverter(DateTimeZoneProviders.Serialization));
}
}
public class AcTypeContractResolver : DefaultContractResolver
{
private readonly Predicate<object> _predicate;
private readonly Func<MemberInfo, Predicate<object>> _predicateFactory;
public AcTypeContractResolver(Predicate<object> predicate)
{
_predicate = predicate;
}
public AcTypeContractResolver(Func<MemberInfo, Predicate<object>> predicateFactory)
{
_predicateFactory = predicateFactory;
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
property.Ignored = false;
property.ShouldSerialize = _predicate ?? _predicateFactory?.Invoke(member);
property.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
return property;
}
}
public class ZonedTimeDetails
{
[JsonConstructor]
public ZonedTimeDetails(ZonedDateTime zoneStart, ZonedDateTime zoneEnd, bool isOverflow = false)
{
ZonedStart = zoneStart;
ZonedEnd = zoneEnd;
IsOverflow = isOverflow;
}
public ZonedDateTime ZonedStart { get; private set; }
public ZonedDateTime ZonedEnd { get; private set; }
public bool IsOverflow { get; private set; }
public DateTime Start => ZonedStart.ToDateTimeUnspecified();
public DateTime End => ZonedEnd.ToDateTimeUnspecified();
public double DurationMin => (ZonedEnd - ZonedStart).TotalMinutes;
}
这是整个项目,如果对您有帮助的话: https://mega.nz/#!hFc0RAbS!teJ3Y4JHqCx1aHxUVU4kUFs30xwTTyF6QTpRB0D1Fnw
如果有人知道出了什么问题,请告诉我。
据我所知,问题出在 ZonedTimeDetails
class,但我相信这应该有效。 class 的 属性 名称与 ctor 参数名称相匹配,所以我不明白为什么我在反序列化过程中得到错误的值。
更新:
如果我为 ZonedDateTime
属性 public 创建设置器,它可以工作,但我需要 class 是不可变的。根据 SO (1, 2) 上的其他答案,此构造函数注入应该有效。
除此之外,在我使用 ZonedDateTime
之前,我在那个 class 中使用了 DateTime
属性。使用 setter private 一切正常。
问题是 ZonedTimeDetails
构造函数中的参数名称与 JSON 不匹配,后者是通过序列化同一个 class 创建的。 属性 名称有一个 d
(例如 ZonedStart
),而构造函数 属性 名称没有(zoneStart
)。因此,当调用构造函数时,会将空结构传递给这些参数。
要修复,只需更改构造函数参数名称以匹配 属性 名称:
[JsonConstructor]
public ZonedTimeDetails(ZonedDateTime zonedStart, ZonedDateTime zonedEnd, bool isOverflow = false)
{
ZonedStart = zonedStart;
ZonedEnd = zonedEnd;
IsOverflow = isOverflow;
}