使用Json.net反序列化具有父子关系的对象图时,使用非默认构造函数会破坏反序列化顺序,导致子对象在其父对象之前进行反序列化(构造和属性分配),从而导致空引用。
经过实验,所有非默认构造函数对象似乎仅在所有默认构造函数对象之后实例化,而且奇怪的是,它们似乎按照序列化的相反顺序(先子后父)进行。
这会导致“子”对象应该引用其父对象(并正确序列化)的情况下,却被反序列化为null值。
这似乎是一个非常常见的情况,所以我想知道是否有遗漏的东西?
是否有设置可以更改此行为?对于其他情况,它是否是设计上的问题?除了全面创建默认构造函数外,是否有其他解决方法?
使用LINQPad或DotNetFiddle进行简单示例:
使用具有非默认构造函数的Middle输出:
经过实验,所有非默认构造函数对象似乎仅在所有默认构造函数对象之后实例化,而且奇怪的是,它们似乎按照序列化的相反顺序(先子后父)进行。
这会导致“子”对象应该引用其父对象(并正确序列化)的情况下,却被反序列化为null值。
这似乎是一个非常常见的情况,所以我想知道是否有遗漏的东西?
是否有设置可以更改此行为?对于其他情况,它是否是设计上的问题?除了全面创建默认构造函数外,是否有其他解决方法?
使用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