C#中处理API返回JSON空数组与对象的反序列化问题
解决方案
问题根源在于API返回的data和errors字段类型动态切换:正常场景下data是对象、errors是空数组;错误场景下data是空数组、errors是对象,现有模型无法兼容两种类型,导致反序列化失败。以下是两种可行的解决方式:
方案一:自定义Json转换器(类型安全,推荐)
步骤1:实现通用转换逻辑
创建两个自定义JsonConverter,分别处理「对象/空数组」和「数组/对象」的动态转换:
// 用于data字段:兼容对象或空数组,空数组时返回null public class ObjectOrEmptyArrayConverter<T> : JsonConverter<T> { public override T ReadJson(JsonReader reader, Type objectType, T existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.StartArray) { var array = JArray.Load(reader); return array.Count == 0 ? default(T) : throw new JsonSerializationException("非空数组无法转换为目标对象类型"); } else if (reader.TokenType == JsonToken.StartObject) { return serializer.Deserialize<T>(reader); } return default(T); } public override void WriteJson(JsonWriter writer, T value, JsonSerializer serializer) { serializer.Serialize(writer, value); } } // 用于errors字段:兼容数组或单个对象,对象时自动包装为List public class ArrayOrObjectConverter<T> : JsonConverter<List<T>> { public override List<T> ReadJson(JsonReader reader, Type objectType, List<T> existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.StartObject) { var obj = serializer.Deserialize<T>(reader); return new List<T> { obj }; } else if (reader.TokenType == JsonToken.StartArray) { return serializer.Deserialize<List<T>>(reader); } return new List<T>(); } public override void WriteJson(JsonWriter writer, List<T> value, JsonSerializer serializer) { serializer.Serialize(writer, value); } }
步骤2:更新模型并添加转换器特性
为模型的data和errors字段绑定对应的转换器:
public class RequestPaymentVerifyResponseModel { [JsonConverter(typeof(ObjectOrEmptyArrayConverter<VerifyData>))] public VerifyData data { get; set; } [JsonConverter(typeof(ArrayOrObjectConverter<Errors>))] public List<Errors> errors { get; set; } } public class VerifyData { public int code { get; set; } public string message { get; set; } public string card_hash { get; set; } public string card_pan { get; set; } public int ref_id { get; set; } public string fee_type { get; set; } public int fee { get; set; } } public class Errors { public int code { get; set; } public string message { get; set; } public List<object> validations { get; set; } }
步骤3:使用原有反序列化代码
现在可以直接复用你的原代码,两种返回格式都会被正确处理:
var result = await client.PostAsJsonAsync("pg/v4/payment/verify.json", parameters); var response = JsonConvert.DeserializeObject<RequestPaymentVerifyResponseModel>(await result.Content.ReadAsStringAsync());
方案二:手动解析JToken(快速实现)
如果不想编写自定义转换器,可先将JSON解析为JObject,手动判断字段类型后再转换为目标模型:
var result = await client.PostAsJsonAsync("pg/v4/payment/verify.json", parameters); var jsonString = await result.Content.ReadAsStringAsync(); var jRoot = JObject.Parse(jsonString); var response = new RequestPaymentVerifyResponseModel(); // 处理data字段 if (jRoot["data"].Type == JTokenType.Object) { response.data = jRoot["data"].ToObject<VerifyData>(); } else { // 错误场景下data是空数组,设为null response.data = null; } // 处理errors字段 if (jRoot["errors"].Type == JTokenType.Object) { // 错误场景下errors是单个对象,包装为List response.errors = new List<Errors> { jRoot["errors"].ToObject<Errors>() }; } else { // 正常场景下errors是空数组,直接转换为List response.errors = jRoot["errors"].ToObject<List<Errors>>(); }
内容的提问来源于stack exchange,提问作者Ali Jebali
相关产品推荐
相关产品推荐

