我和我的团队在使用C#中的JSON.NET反序列化过程中遇到了一个奇怪的行为。
我们有一个简单的ViewModel,其中包含一个IOrderedEnumerable<long>
:
public class TestClass
{
public IOrderedEnumerable<long> orderedDatas { get; set; }
public string Name { get; set; }
public TestClass(string name)
{
this.Name = name;
this.orderedDatas = new List<long>().OrderBy(p => p);
}
}
然后,我们只需将此视图模型POST/PUT到API控制器中。
[HttpPost]
public IHttpActionResult Post([FromBody]TestClass test)
{
return Ok(test);
}
调用此API时,需要使用类似以下JSON格式的数据:
{
Name: "tiit",
"orderedDatas": [
2,
3,
4
],
}
通过这个调用,我们发现构造函数没有被调用(这可以解释为它不是默认构造函数)。但奇怪的是,如果我们将集合类型更改为 IEnumerable 或 IList,则构造函数将被正确调用。
如果我们将 TestClass 的构造函数更改为默认构造函数:
public class TestClass
{
public IOrderedEnumerable<long> orderedDatas { get; set; }
public string Name { get; set; }
public TestClass()
{
this.Name = "default";
this.orderedDatas = new List<long>().OrderBy(i => i);
}
}
控制器检索到的对象不会为空。如果我们将集合的类型更改为
IEnumerable
并保留带有参数的构造函数(public TestClass(string name)
),那么它也可以工作。另一个奇怪的事情是,控制器中的对象为 "null"。不仅 orderedDatas 为空,整个对象都为空。
如果在类上添加属性
[JsonObject]
,并在属性 orderedData 上添加 [JsonIgnore]
,则它将起作用。目前,我们将对象更改为简单的 List,并且它工作得很好,但我们想知道为什么根据集合类型,JSON 反序列化表现出不同的行为。
如果我们直接使用 JsonConvert.Deserialize:
var json = "{ Name: 'tiit', 'orderedDatas': [2,3,4,332232] }";
var result = JsonConvert.DeserializeObject<TestClass>(json);
我们可以看到实际的异常信息:
如果有任何想法/帮助,将不胜感激。无法创建和填充列表类型 System.Linq.IOrderedEnumerable`1[System.Int64]。路径 'orderedDatas', 第1行,第33个位置。
谢谢!
**编辑:谢谢你们的答复。有一件事我一直发现很奇怪(我用粗体标出来了),如果你有任何想法来解释这种行为,请告诉我**
IOrderedEnumerable
只是一个接口。列表和数组不是有序的,因此它们不实现该接口。如果您想要使用特定的集合类型而不是数组,则应该使用自定义转换器来创建所需的类型(例如SortedList)。 - Panagiotis Kanavos