当尝试使用Newtonsoft的Json.NET nuget库反序列化某些Json时,如果我不提供JsonSerializerSettings-为什么?我的collection- properties为null ?
JsonSerializerSettings
我有一些有效的json数据,并将其反序列化为我的自定义类/ POCO。现在,所有简单的属性(例如strings,int‘s等)都已正确设置。我的简单子类也已正确设置(例如,User属性或BuildingDetails属性等)。
string
int
User
BuildingDetails
我所有的收藏都是null。这些设置器永远不会被调用(我在其中设置了一个断点,但它们没有被设置,但是其他设置器却被调用/设置了)。
null
例如。属性。
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
现在-这是疯狂的事情:当我使用a时,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。这是使事情正常进行的神奇设置。
ObjectCreationHandling = ObjectCreationHandling.Replace
这是什么做的?为什么 不能 有这个设置意味着我的收藏品都没有得到集/创建/等?
另一个线索。如果我 没有 二传手,则collection为null /未设置。如果我有这样的二传手,它也会失败:
public List<Media> Images { get { return new List<Media> { new Media{..}, new Media{..} }; } set { AddImages(value); } }
如果我不返回列表,则getter在集合中为SET!有用!
getter
private List<Media> _images; public List<Media> Images { get { return _images; } set { AddImages(value); } }
请注意,现在如何仅使用烘烤场?
就像集合的GETTER属性和结果之间存在一些奇怪的连接/关联,以及Json.net如何使用auto设置来设置此数据?
auto
您的问题是,您要反序列化的属性在对象图中获取并设置了 代理 集合,而不是“真实”集合。这样做违反了Json.NET用于构造和填充返回参考类型对象,集合和词典的属性的算法的实现决策。该算法是:
它在父类中调用getter以获取要反序列化的属性的当前值。
如果为null,并且除非使用自定义构造函数,否则它将分配属性的返回类型的实例(使用该类型的JsonContract.DefaultCreator方法)。
JsonContract.DefaultCreator
它调用父级中的setter,以将分配的实例设置回父级中。
它将继续填充类型的实例。
实例填充后,它不会将实例再次设置回第二次。
在开始时调用getter可以填充类型的实例(例如使用JsonConvert.PopulateObject()),然后递归地填充该类型所引用的其他类型的任何预分配实例。(这就是中的existingValue参数的目的JsonConverter.ReadJson()。)
JsonConvert.PopulateObject()
existingValue
JsonConverter.ReadJson()
但是,以这种方式填充预分配的对象图的能力是有代价的:图中遇到的每个对象必须是 真实 对象,而不是为序列化目的创建的某些代理对象。如果getter返回的对象只是某个代理,则将填充该代理,而不填充“真实”对象- 除非该代理具有某种机制,以将对其数据的更改传递回其始发者。
ObjectCreationHandling =ObjectCreationHandling.Replace如您所见,更改了该算法,以便对集合进行分配,填充和设置。这是启用代理集合反序列化的一种方法。
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,因为在完全读取之前无法知道大小,因此无法分配数组并在完全读取之前将其设置回去。
XmlSerializer
(您也可以使用代理技巧ObservableCollection,但是我不推荐这样做。)
ObservableCollection