uri*_*rig 7 serialization types json.net
当我将Json.NET设置为序列化并将TypeNameHandling设置为TypeNameHandling.Auto时,它正确地为对象的子属性设置$ type,但是对于被序列化的根对象没有这样做.为什么?
请考虑以下repro:
public class Animal
{
public Animal[] Offspring { get; set; }
}
public class Dog : Animal {}
Animal fido = new Dog
{
Offspring = new Animal[] { new Dog() }
};
var json = JsonConvert.SerializeObject(fido,
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto
});
Run Code Online (Sandbox Code Playgroud)
发送到json变量的Json 是:
{
"Offspring": [{
"$type": "MyApp.Dog, MyApp",
"Offspring": null
}]
}
Run Code Online (Sandbox Code Playgroud)
Json.NET 文档说,TypeNameHandling.Auto行为是:
当序列化对象的类型与其声明的类型不同时,请包含.NET类型名称.
我的问题是 - 为什么fido不
"$type": "MyApp.Dog, MyApp",喜欢它的小狗?:)
更新:我从这个问题的接受答案中发现,我可以通过执行以下操作强制添加$ type:
var json = JsonConvert.SerializeObject(fido,
typeof(Animal),
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
Formatting = Formatting.Indented
});
Run Code Online (Sandbox Code Playgroud)
但我的问题仍然存在 - 为什么Json.NET不按照文档自行执行此操作?
简短的回答:它不是因为它不能.
正如您在问题中所述,当被序列化的对象的实际(运行时)类型与其声明的(编译时)类型不同时,设置TypeNameHandling为Auto指示Json.Net包含.NET类型名称.为了做到这一点,Json.Net需要知道每个对象的两种类型.
对于根对象内部的所有内容,这很简单:只需获取根对象的运行时类型GetType(),然后使用反射获取其所有声明的属性及其类型,并为每个属性将声明的类型与实际类型进行比较如果他们不一样 如果是,则输出类型名称.
但对于根对象本身,Json.Net无法访问这两种类型.它拥有的所有信息都是引用的对象fido,其运行时类型为Dog.除非你以某种方式提供该上下文,否则Json.Net无法发现fido变量被声明为Animal.这就是为什么Json.Net提供的重载SerializeObject允许您指定被序列化对象的编译时类型的原因.你必须,如果你想利用这些重载之一TypeNameHandling.Auto设置为根对象工作.