当我将Json.NET设置为使用TypeNameHandling设置为TypeNameHandling.Auto进行序列化时,它会正确设置对象的子属性的$ type,但不会对要序列化的根对象设置$ type。为什么呢?
请考虑以下代表:
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
});
发送到json
变量的Json是:
{
"Offspring": [{
"$type": "MyApp.Dog, MyApp",
"Offspring": null
}]
}
Json.NET Documentation表示,对于TypeNameHandling.Auto
,行为是:
当要序列化的对象的类型与其声明的类型不同时,请包含.NET类型名称。
我的问题是 - 为什么fido没有
"$type": "MyApp.Dog, MyApp",
喜欢它的小狗? :)
更新:我已从this question的已接受答案中发现我可以通过执行以下操作强制添加$ type:
var json = JsonConvert.SerializeObject(fido,
typeof(Animal),
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Auto,
Formatting = Formatting.Indented
});
但我的问题仍然存在 - 为什么Json.NET不按照文档自行完成?
答案 0 :(得分:6)
简短回答:不是因为不能。
正如您在问题中所述,将TypeNameHandling
设置为Auto
会指示Json.Net在要序列化的对象的实际(运行时)类型不是时包含.NET类型名称与其声明的(编译时)类型相同。为了做到这一点,Json.Net需要知道每个对象的两种类型。
对于根对象内的所有内容,这很简单:只需通过GetType()
获取根对象的运行时类型,然后使用反射获取其所有声明的属性及其类型,并为每个属性进行比较声明类型为实际类型以查看它们是否不同。如果是,则输出类型名称。
但是对于根对象本身,Json.Net无法访问这两种类型。它拥有的所有信息都是fido
引用的对象,其运行时类型为Dog
。 Json.Net无法发现fido
变量被声明为Animal
,除非您以某种方式提供该上下文。这正是Json.Net提供SerializeObject
重载的原因,它允许您指定要序列化的对象的编译时类型。如果希望TypeNameHandling.Auto
设置适用于根对象,则必须使用其中一个重载。
答案 1 :(得分:1)
Brian绝对正确,当AVCaptureConnection
参数声明为times = c(0,30,60,90,120,180,240)
# Transpose cin dataframe
cin <- as.data.frame(t(cin[,2:8]))
# Apply the calculation to each column and bind results to bottom of dataframe
cin <- rbind(cin, apply(cin, 2, function(x) sum(diff(times[order(times)])*rollmean(x,2))))
# Set rowname for calculation to "AUC"
row.names(cin)[length(row.names(cin))] <- "AUC"
# Transpose cin dataframe back to original format
cin <- as.data.frame(t(cin))
时,Json.NET无法知道传递的对象的编译时声明类型。对此的简单修复是,如果Json.NET添加了通用序列化方法,那么编译时声明的类型将自动转移到Json.NET,但库的作者已决定反对我对此here的提议。
作为替代方案,我在value
类中包含了所有json(de)序列化需求,并使用通用序列化方法,这些方法使用object
表达式自动传递编译时声明的类型要序列化的值。
答案 2 :(得分:0)
较新版本的Json.Net允许您将期望的类型传递给序列化方法
ser.Serialize(stream, rootObject, typeof(BaseClass));
您可以将基类传递给serialize方法,如果对象和预期类型不匹配,TypeNameHandling.Auto
将写入$ type。