REST API响应中Address字段时而为对象时而为列表的反序列化问题
解决JSON反序列化时单个对象/数组兼容问题(Address字段)
问题场景
调用同一REST API获取JSON响应时,反序列化会报错,原因是响应中的Address字段格式不固定:存在多个地址时返回数组,仅一个地址时返回单个对象,导致无法直接用List<Address>类型完成反序列化。
以下是两种响应示例及原反序列化代码:
返回Address为数组的JSON
{ "ResponseStatus": { "Code": "1", "Description": "Success" }, "Address": [ { "City": "CLEVELAND", "State": "OH", "PostalCode": "44126", "CountryCode": "US" }, { "City": "CLEVELAND", "State": "WV", "PostalCode": "26215", "CountryCode": "US" } ] }
返回Address为单个对象的JSON
{ "ResponseStatus": { "Code": "1", "Description": "Success" }, "Address": { "City": "CLEVELAND", "State": "OH", "PostalCode": "44126", "CountryCode": "US" } }
原反序列化C#类代码
public class Address { public string City { get; set; } public string State { get; set; } public string PostalCode { get; set; } public string CountryCode { get; set; } } public class ResponseStatus { public string Code { get; set; } public string Description { get; set; } } public class Response { public ResponseStatus ResponseStatus { get; set; } public List<Address> Address { get; set; } } // 单个对象场景下会报错的反序列化代码 Response result = JsonConvert.DeserializeObject<Response>(response);
解决方案:自定义JSON转换器
通过实现JsonConverter统一处理两种格式的转换逻辑,将单个对象或数组都转为List<Address>类型。
1. 实现自定义转换器
public class SingleOrArrayConverter<T> : JsonConverter<List<T>> { public override List<T> ReadJson(JsonReader reader, Type objectType, List<T> existingValue, bool hasExistingValue, JsonSerializer serializer) { var token = JToken.Load(reader); return token.Type switch { JTokenType.Array => token.ToObject<List<T>>(), JTokenType.Object => new List<T> { token.ToObject<T>() }, _ => throw new JsonSerializationException($"Unexpected token type: {token.Type}") }; } public override void WriteJson(JsonWriter writer, List<T> value, JsonSerializer serializer) { // 可选:序列化时根据列表长度自动输出单个对象或数组 if (value.Count == 1) { serializer.Serialize(writer, value[0]); } else { serializer.Serialize(writer, value); } } }
2. 修改Response类绑定转换器
在Address属性上添加特性,指定使用自定义转换器:
public class Response { public ResponseStatus ResponseStatus { get; set; } [JsonConverter(typeof(SingleOrArrayConverter<Address>))] public List<Address> Address { get; set; } }
3. 测试反序列化
修改后两种格式的JSON都能正常完成反序列化:
// 单个对象场景 var singleResponse = "{...单个Address的JSON内容...}"; var result1 = JsonConvert.DeserializeObject<Response>(singleResponse); // result1.Address 包含1个Address元素 // 数组场景 var arrayResponse = "{...Address数组的JSON内容...}"; var result2 = JsonConvert.DeserializeObject<Response>(arrayResponse); // result2.Address 包含多个Address元素
替代方案:动态手动处理(不推荐)
如果不想编写自定义转换器,也可以先将JSON解析为JObject,手动判断Address的类型后再转换:
var jObject = JObject.Parse(response); var responseObj = new Response { ResponseStatus = jObject["ResponseStatus"].ToObject<ResponseStatus>() }; var addressToken = jObject["Address"]; responseObj.Address = addressToken.Type switch { JTokenType.Array => addressToken.ToObject<List<Address>>(), JTokenType.Object => new List<Address> { addressToken.ToObject<Address>() }, _ => new List<Address>() };
此方式代码冗余、复用性差,仅适合临时场景。
内容的提问来源于stack exchange,提问作者Shibu
相关产品推荐
相关产品推荐

