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

Pur*_*ome 3 .net c# json

问题

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

细节

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

我所有的收藏都是null。这些设置器永远不会被调用(我在其中设置了一个断点,但它们没有被设置,但是其他设置器却被调用/设置了)。

例如。属性。

List<Media> Images { get { ... } set { ... } }
Run Code Online (Sandbox Code Playgroud)

例如。

var foo = new Foo();
var json = JsonConvert.Serialize(foo);
var anotherFoo = JsonConvert.Deserialize<Foo>(json);

// the collection properties on anotherFoo are null
Run Code Online (Sandbox Code Playgroud)

现在-这是疯狂的事情:当我使用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);
Run Code Online (Sandbox Code Playgroud)

我的收藏集已设定!

请注意:ObjectCreationHandling = ObjectCreationHandling.Replace。这是使事情正常进行的神奇设置。

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

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

public List<Media> Images
{
    get { return new List<Media> { new Media{..}, new Media{..} }; }
   set { AddImages(value); }
}
Run Code Online (Sandbox Code Playgroud)

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

private List<Media> _images;
public List<Media> Images
{
    get { return _images; }
    set { AddImages(value); }
}
Run Code Online (Sandbox Code Playgroud)

请注意,现在如何仅使用烘焙字段?

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

dbc*_*dbc 5

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

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

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

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

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

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

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

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

(虽然这个决定似乎是不合需要的,但这并不罕见;XmlSerializer 以相同的方式工作。有关执行此操作的序列化程序的列表,请参见具有代码默认值的XML集合属性的反序列化。)

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); }
}
Run Code Online (Sandbox Code Playgroud)

对于数组,Json.NET(和XmlSerializer必须在完全读取数组后调用setter,因为要等到完全读取后才能知道大小,因此要分配数组,并要等到完全读取后才能将其设置回去。

(您也可以使用代理技巧ObservableCollection,但是我不推荐这样做。)


归档时间:

查看次数:

376 次

最近记录:

6 年,4 月 前