使用 .NET Newtonsoft.Json 组件反序列化某些有效 json 时,为啥我的 POCO 中的所有集合都为空
Posted
技术标签:
【中文标题】使用 .NET Newtonsoft.Json 组件反序列化某些有效 json 时,为啥我的 POCO 中的所有集合都为空【英文标题】:Why are all the collections in my POCO are null when deserializing some valid json with the .NET Newtonsoft.Json component使用 .NET Newtonsoft.Json 组件反序列化某些有效 json 时,为什么我的 POCO 中的所有集合都为空 【发布时间】:2015-12-06 03:43:54 【问题描述】:问题
当尝试使用 Newtonsoft 的 Json.NET nuget 库反序列化某些 Json 时,如果我不提供 JsonSerializerSettings
,我的集合属性为空 - 为什么?
详情
我有一些有效的 json 数据并将其反序列化到我的自定义类/POCO 中。现在,所有简单属性(如string
s、int
's 等)都已正确设置。我的简单子类也得到了正确设置(例如User
属性或BuildingDetails
属性等)。
不过,我所有的收藏都是null
。 setter 永远不会被调用(我已经在其中设置了一个断点并且它们没有被设置,但其他的确实被调用/设置)。
例如。属性。
List<Media> Images get ... set ...
例如。
var foo = new Foo();
var json = JsonConvert.Serialize(foo);
var anotherFoo = JsonConvert.Deserialize<Foo>(json);
// the collection properties on anotherFoo are null
现在 - 这太疯狂了:当我使用 JsonSerializerSettings
时,它现在可以工作了:
// NOTE: ModifiedDataContractResolver <-- skips any property that is a type
/ ModifiedData (which is a simple custom class I have).
var settings = new JsonSerializerSettings
ContractResolver = new ModifiedDataContractResolver(),
ObjectCreationHandling = ObjectCreationHandling.Replace,
Formatting = Formatting.Indented
;
var foo = new Foo();
var json = JsonConvert.Serialize(foo, settings);
var anotherFoo = JsonConvert.Deserialize<Foo>(json, settings);
我的收藏现在已经设置好了!
请注意:ObjectCreationHandling = ObjectCreationHandling.Replace
。这是使事情顺利进行的神奇设置。
这是在做什么?为什么没有有这个设置意味着我的集合没有被设置/创建/等等?
另一个线索。如果我 not 有设置器,则集合为空/未设置。如果我有这样的二传手,它也会失败:
public List<Media> Images
get return new List<Media> new Media.., new Media.. ;
set AddImages(value);
如果我不返回列表,则在getter
中,集合已设置!它有效!
private List<Media> _images;
public List<Media> Images
get return _images;
set AddImages(value);
注意它现在只是使用烘焙场了吗?
好像集合的 GETTER 属性和结果之间存在一些奇怪的联系/关联,以及 Json.net 如何使用 auto
设置设置这些数据?
【问题讨论】:
相关:XML Deserialization of collection property with code defaults(问题是关于 XML,但答案提到了 Json.NET)。 【参考方案1】:您的问题是您尝试反序列化的属性获取并设置了一个 proxy 集合,而不是对象图中的“真实”集合。这样做违反了关于 Json.NET 用于构造和填充返回引用类型对象、集合和字典的属性的算法的实现决策。该算法是:
调用父类中的getter获取被反序列化的属性的当前值。
如果为 null,除非使用自定义 constructor,否则它会分配属性返回类型的实例(使用该类型的 JsonContract.DefaultCreator
方法)。
它调用父级中的setter将分配的实例设置回父级。
它继续填充该类型的实例。
在填充实例后,它不会再次将其设置回去。
在开始时调用 getter 可以填充一个类型的实例(例如使用JsonConvert.PopulateObject()
),递归地填充该类型所引用的其他类型的任何预分配实例。 (这就是JsonConverter.ReadJson()
中existingValue
参数的用途。)
但是,以这种方式填充预分配对象图的能力是有代价的:图中遇到的每个对象都必须是 真实 对象,而不是为序列化目的而创建的某些代理对象.如果 getter 返回的对象只是某个代理,则代理将被填充,而不是“真实”对象 - 除非代理具有某种机制将其数据的更改传递回其发起者。
(虽然这个决定可能看起来不受欢迎,但这并不罕见;XmlSerializer
works the same way。有关执行此操作的序列化程序列表,请参阅XML Deserialization of collection property with code defaults。)
ObjectCreationHandling = ObjectCreationHandling.Replace
,正如您所观察到的,更改了此算法,以便分配、填充和设置集合。这是启用代理集合反序列化的一种方法。
作为另一种解决方法,您可以选择序列化和反序列化代理数组:
[JsonIgnore]
public List<Media> Images
get return new List<Media> new Media.., new Media.. ;
set AddImages(value);
[JsonProperty("Images")] // Could be private
Media [] ImagesArray
get return Images.ToArray();
set AddImages(value);
对于数组,Json.NET(和XmlSerializer
)必须在数组被完全读取后调用setter,因为在完全读取之前无法知道大小,因此无法分配数组并返回直到完全阅读。
(您也可以使用代理 ObservableCollection
进行技巧,但我不建议这样做。)
【讨论】:
我想我的脑袋都快疯了:/ 我需要读这个大约 10 次,我觉得...以上是关于使用 .NET Newtonsoft.Json 组件反序列化某些有效 json 时,为啥我的 POCO 中的所有集合都为空的主要内容,如果未能解决你的问题,请参考以下文章
asp.net环境下对 Newtonsoft.json 引用的设置问题
.Net使用Newtonsoft.Json.dll(JSON.NET)对象序列化成json反序列化json示例教程
如何使用 NewtonSoft Json.Net 将 Json 字典反序列化为平面类
在Asp.Net Core 3.0中如何使用 Newtonsoft.Json 库序列化数据