一尘不染

使用.NET Newtonsoft.Json组件反序列化某些有效json时,为什么POCO中的所有集合都为null

json

问题

当尝试使用Newtonsoft的Json.NET
nuget库反序列化某些Json时,如果我不提供JsonSerializerSettings-为什么?我的collection-
properties为null ?

细节

我有一些有效的json数据,并将其反序列化为我的自定义类/
POCO。现在,所有简单的属性(例如strings,int‘s等)都已正确设置。我的简单子类也已正确设置(例如,User属性或BuildingDetails属性等)。

我所有的收藏都是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。这是使事情正常进行的神奇设置。

这是什么做的?为什么 不能 有这个设置意味着我的收藏品都没有得到集/创建/等?

另一个线索。如果我 没有 二传手,则collection为null /未设置。如果我有这样的二传手,它也会失败:

public List<Media> Images
{
    get { return new List<Media> { new Media{..}, new Media{..} }; }
   set { AddImages(value); }
}

如果我不返回列表,则getter在集合中为SET!有用!

private List<Media> _images;
public List<Media> Images
{
    get { return _images; }
    set { AddImages(value); }
}

请注意,现在如何仅使用烘烤场?

就像集合的GETTER属性和结果之间存在一些奇怪的连接/关联,以及Json.net如何使用auto设置来设置此数据?


阅读 275

收藏
2020-07-27

共1个答案

一尘不染

您的问题是,您要反序列化的属性在对象图中获取并设置了 代理
集合,而不是“真实”集合。这样做违反了Json.NET用于构造和填充返回参考类型对象,集合和词典的属性的算法的实现决策。该算法是:

  1. 它在父类中调用getter以获取要反序列化的属性的当前值。

  2. 如果为null,并且除非使用自定义构造函数,否则它将分配属性的返回类型的实例(使用该类型的JsonContract.DefaultCreator方法)。

  3. 它调用父级中的setter,以将分配的实例设置回父级中。

  4. 它将继续填充类型的实例。

  5. 实例填充后,它不会将实例再次设置回第二次。

在开始时调用getter可以填充类型的实例(例如使用JsonConvert.PopulateObject()),然后递归地填充该类型所引用的其他类型的任何预分配实例。(这就是中的existingValue参数的目的JsonConverter.ReadJson()。)

但是,以这种方式填充预分配的对象图的能力是有代价的:图中遇到的每个对象必须是 真实
对象,而不是为序列化目的创建的某些代理对象。如果getter返回的对象只是某个代理,则将填充该代理,而不填充“真实”对象-
除非该代理具有某种机制,以将对其数据的更改传递回其始发者。

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,但是我不推荐这样做。)

2020-07-27