根据Json.Net documentation,所有IEnumerable
类型都应序列化为json数组。
所以我期待以下课程:
public class MyClass
{
public IEnumerable<string> Values { get; set; }
}
序列化为:
{
"Values": []
}
问题在于,当我使用TypeNameHandling=Auto
时,我得到:
{
"Values": {
"$type": "System.String[], mscorlib",
"$values": []
}
}
我需要TypeNameHandling=Auto
用于其他属性,但我希望IEnumerable
使用默认序列化。其他类型(例如IList
)按预期工作。
这是一个错误还是我错过了什么?
这里是重现问题的完整代码:
[Test]
public void Newtonsoft_serialize_list_and_enumerable()
{
var target = new Newtonsoft.Json.JsonSerializer
{
TypeNameHandling = TypeNameHandling.Auto
};
var myEvent = new MyClass
{
Values = new string[0]
};
var builder = new StringWriter();
target.Serialize(builder, myEvent);
var json = JObject.Parse(builder.ToString());
Assert.AreEqual(JTokenType.Array, json["Values"].Type);
}
public class MyClass
{
public IEnumerable<string> Values { get; set; }
}
我正在使用Newtonsoft 7.0.1。
更新: 这里使用更多类型的另一个测试:
[Test]
public void Newtonsoft_serialize_list_and_enumerable()
{
var target = new Newtonsoft.Json.JsonSerializer
{
TypeNameHandling = TypeNameHandling.Auto
};
var myEvent = new MyClass
{
Values1 = new string[0],
Values2 = new List<string>(),
Values3 = new string[0],
Values4 = new List<string>(),
Values5 = new string[0]
};
var builder = new StringWriter();
target.Serialize(builder, myEvent);
var json = builder.ToString();
}
public class MyClass
{
public IEnumerable<string> Values1 { get; set; }
public IEnumerable<string> Values2 { get; set; }
public IList<string> Values3 { get; set; }
public IList<string> Values4 { get; set; }
public string[] Values5 { get; set; }
}
这就是结果:
{
"Values1": {
"$type": "System.String[], mscorlib",
"$values": []
},
"Values2": [],
"Values3": {
"$type": "System.String[], mscorlib",
"$values": []
},
"Values4": [],
"Values5": []
}
我再也不明白为什么根据组合得到不同的结果。
答案 0 :(得分:4)
在反序列化为IEnumerable
或IList
字段时,Json.Net的默认自动行为是创建List
实例。如果您分配Array
实例,那么将对象恢复到原始实例状态的唯一方法是让Json.Net添加$type
元数据,这就是您所看到的。 即。有很多方法可以反序列化为IEnumerable
字段。
使用List<string>
实例:
var myEvent = new MyClass
{
Values = new List<string>(),
};
使用:
public class MyClass
{
public IEnumerable<string> Values { get; set; }
}
结果(序列化时):
{"Values":["hello"]}
此外,如果您使用显式可构造类型或使用默认List,那么Json.Net将使用它并省略$type
;
例如:
string[] Values { get; set; } = new string[0]; // not needed
IEnumerable<string> Values { get; set; } = new string[0]; //$type needed
IEnumerable<string> Values { get; set; } = new Stack<string>(); //$type needed
IEnumerable<string> Values { get; set; } = new List<string>; // not needed
List<string> Values { get; set; } = new List<string>; // not needed
ObservableCollection<string> Values { get; set; } =
new ObservableCollection<string>(); // not needed
答案 1 :(得分:2)
这不是错误,但这是预期的行为。您正在全局设置TypeNameHandling
。您可以使用下面的属性标记属性,而不是全局设置类型名称处理,以避免它们被包含在设置TypeNameHandling.Auto
中:
[JsonProperty(TypeNameHandling = TypeNameHandling.None)]
以下是一个示例:
public class MyClass
{
// Indicate the property not to apply any type handling
[JsonProperty(TypeNameHandling=TypeNameHandling.None)]
public IList<string> Values { get; set; }
public string Name { get; set; }
}
这将为您提供所需的结果,而不会受到全局声明的任何TypeNameHandling
设置的影响。