Newtonsoft.Json反序列化JSON列表返回数与属性数一致异常问题
问题描述
现有如下结构的JSON数据:
[{"query":[{"number":"0000-2022-64129734 / 19:26"},{"location":"xx"},{"date":"01.06.2022"},{"querytype":"uu"},{"reason":"TEST"},{"identitytype":"xx"}]},{"identity":[{"name":"xx"},{"surname":"xx"},{"id":"xx"},{"mothername":"xx"},{"fathername":"xx"},{"birthlocation":"xx"},{"birthday":"05"},{"birthmonth":"05"},{"birthyear":"1964"},{"birthlocationCity":"xx"}]},{"criminal_record_list":[[{"crime":"xx"},{"value":3}]]}]
当前定义的C#反序列化实体类及调用代码如下:
[JsonObject] public class CrimeResultModel { [JsonProperty("criminal_record_list")] public List<List<criminal_record_list>> criminal_record_list{ get; set; } [JsonProperty("query")] public List<query> query{ get; set; } [JsonProperty("identity")] public List<identity> identity{ get; set; } public long CriminalRecordType { get; set; } } public class criminal_record_list { [JsonProperty("crime")] public string crime{ get; set; } [JsonProperty("value")] public int value{ get; set; } } public class query { public string number{ get; set; } public string location{ get; set; } public string date{ get; set; } public string querytype{ get; set; } public string reason{ get; set; } public string identitytype{ get; set; } } public class identity { public string name{ get; set; } public string surname{ get; set; } public string id{ get; set; } public string mothername{ get; set; } public string fathername{ get; set; } public string birthlocation{ get; set; } public string birthday{ get; set; } public string birthmonth{ get; set; } public string birthyear{ get; set; } public string birthlocationCity{ get; set; } } } var result = Newtonsoft.Json.JsonConvert.DeserializeObject<List<CrimeResultModel>>(jsonString);
执行上述反序列化代码时,返回的列表长度与CrimeResultModel类的属性数量一致,各属性对应的子列表长度也与对应实体类的属性数量相等,反序列化结果不符合预期。反序列化异常结果参考截图:
问题原因
- 根结构映射逻辑错误:当前JSON根节点是数组,但数组内的3个元素分别是仅包含
query、identity、criminal_record_list单个属性的零散对象,不是3个完整的CrimeResultModel实例。直接反序列化为List<CrimeResultModel>时,Json.NET会为数组每个元素生成一个独立的CrimeResultModel对象,仅填充元素中存在的单个属性,其余属性为null,最终返回的列表长度为3,恰好和CrimeResultModel的公开属性数量一致。 - 子对象结构映射逻辑错误:JSON中
query、identity对应的数组,内部元素也是一个个独立的单键值对对象(例如{"number":"xxx"}、{"location":"xx"}),不是一个包含所有字段的完整对象。当前定义的query、identity类将所有字段作为类的直接属性,反序列化时每个单键值对对象会生成一个对应的实体实例,仅填充匹配的单个字段,因此子列表长度和对应实体类的属性数量相等。 - 代码存在语法错误:
identity类定义末尾多写了一个闭合大括号},会直接导致编译失败。
解决方案
根据是否可以调整JSON结构,选择对应方案:
方案1:可修改JSON结构(推荐)
调整JSON结构,将根数组改为单个完整对象,同时把query、identity数组内分散的单属性对象合并为单个完整对象,调整后的JSON示例:
{ "query": { "number": "0000-2022-64129734 / 19:26", "location": "xx", "date": "01.06.2022", "querytype": "uu", "reason": "TEST", "identitytype": "xx" }, "identity": { "name": "xx", "surname": "xx", "id": "xx", "mothername": "xx", "fathername": "xx", "birthlocation": "xx", "birthday": "05", "birthmonth": "05", "birthyear": "1964", "birthlocationCity": "xx" }, "criminal_record_list": [ [ {"crime":"xx","value":3} ] ], "CriminalRecordType": 0 }
同步调整实体类定义,修正语法错误,将query、identity属性的类型从列表改为对应实体类型,符合C#命名规范的实体代码如下:
[JsonObject] public class CrimeResultModel { [JsonProperty("criminal_record_list")] public List<List<CriminalRecordItem>> CriminalRecordList{ get; set; } [JsonProperty("query")] public QueryInfo Query{ get; set; } [JsonProperty("identity")] public IdentityInfo Identity{ get; set; } public long CriminalRecordType { get; set; } } public class CriminalRecordItem { [JsonProperty("crime")] public string Crime{ get; set; } [JsonProperty("value")] public int Value{ get; set; } } public class QueryInfo { public string number{ get; set; } public string location{ get; set; } public string date{ get; set; } public string querytype{ get; set; } public string reason{ get; set; } public string identitytype{ get; set; } } public class IdentityInfo { public string name{ get; set; } public string surname{ get; set; } public string id{ get; set; } public string mothername{ get; set; } public string fathername{ get; set; } public string birthlocation{ get; set; } public string birthday{ get; set; } public string birthmonth{ get; set; } public string birthyear{ get; set; } public string birthlocationCity{ get; set; } }
调整反序列化调用代码,直接反序列化为单个CrimeResultModel实例即可:
var result = Newtonsoft.Json.JsonConvert.DeserializeObject<CrimeResultModel>(jsonString);
方案2:不可修改JSON结构
如果无法调整上游返回的JSON格式,需要自定义JsonConverter,在反序列化时先将根数组中分散的三个对象合并为一个完整的CrimeResultModel实例,再遍历query、identity数组内的单属性对象,将属性值逐一赋值到对应的实体实例上,最终返回正确的映射结果。
内容的提问来源于stack exchange,提问作者user3188649
相关产品推荐
相关产品推荐

