【发布时间】:2016-04-26 13:18:39
【问题描述】:
当使用 Json.net 反序列化具有父子关系的对象图时,使用非默认构造函数会破坏反序列化的顺序,使得子对象在其父对象之前被反序列化(构造和分配属性),从而导致空引用。
从实验看来,所有非默认构造函数对象仅在所有默认构造函数对象之后才被实例化,奇怪的是,它似乎与序列化的顺序相反(子对象在父对象之前)。
这会导致应该引用其父对象(并且已正确序列化)的“子”对象被反序列化为空值。
这似乎是一个非常常见的情况,所以我想知道我是否遗漏了什么?
是否有更改此行为的设置?它是否以某种方式设计用于其他场景?除了全面创建默认构造函数之外,还有其他解决方法吗?
使用 LINQPad 或DotNetFiddle 的简单示例:
void Main()
{
var root = new Root();
var middle = new Middle(1);
var child = new Child();
root.Middle = middle;
middle.Root = root;
middle.Child = child;
child.Middle = middle;
var json = JsonConvert.SerializeObject(root, new JsonSerializerSettings
{
Formatting = Newtonsoft.Json.Formatting.Indented,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
PreserveReferencesHandling = PreserveReferencesHandling.All,
TypeNameHandling = TypeNameHandling.All,
});
json.Dump();
//I have tried many different combinations of settings, but they all
//seem to produce the same effect:
var deserialized = JsonConvert.DeserializeObject<Root>(json);
deserialized.Dump();
}
public class Root
{
public Root(){"Root".Dump();}
public Middle Middle {get;set;}
}
public class Middle
{
//Uncomment to see correct functioning:
//public Middle(){"Middle".Dump();}
public Middle(int foo){"Middle".Dump();}
public Root Root {get;set;}
public Child Child {get;set;}
}
public class Child
{
public Child(){"Child".Dump();}
public Middle Middle {get;set;}
}
JSON 输出:
{
"$id": "1",
"$type": "Root",
"Middle": {
"$id": "2",
"$type": "Middle",
"Root": {
"$ref": "1"
},
"Child": {
"$id": "3",
"$type": "Child",
"Middle": {
"$ref": "2"
}
}
}
}
Middle 的输出具有非默认构造函数:
Root
Child
Middle
Child.Middle = null
Middle 的输出具有默认构造函数:
Root
Middle
Child
Child.Middle = Middle
【问题讨论】:
-
@JonSkeet 谢谢,已添加!
-
您使用的是哪个版本的 Json.NET?
-
@dbc 它出现在最新的 nuget 包(8.0.3)中,我已经在 5.0.8 上对它进行了同样的测试 - 这让我认为这是设计使然(虽然我不明白)。
-
release notes for 7.0.1 包含一个注释修复 - 修复了具有只读属性的保留对象引用 -- 但在该版本或更高版本中并未修复它。
标签: c# serialization json.net