C#解析JSON时同一属性兼具对象与列表类型的解决方法
这问题我太熟了!JSON里字段时而对象时而数组的情况真的很坑,尤其是反序列化的时候直接炸类型错误。别担心,咱们用自定义JSON转换器就能完美解决,顺便给你讲讲需要学习的核心知识点。
解决方法:自定义JSON转换器处理“单对象/数组”兼容问题
你用的是Newtonsoft.Json(Json.NET)对吧?它支持自定义JsonConverter来处理这种类型不稳定的字段。咱们先写一个通用的转换器,能把单个对象自动包装成列表,也能直接解析数组,这样所有类似的字段都能复用这个转换器。
步骤1:实现通用的SingleOrArrayConverter
这个转换器会自动判断JSON节点是对象还是数组,然后统一转成List<T>:
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; public class SingleOrArrayConverter<T> : JsonConverter { // 告诉Json.NET这个转换器能处理List<T>类型 public override bool CanConvert(Type objectType) { return objectType == typeof(List<T>); } // 反序列化逻辑:读JSON时处理单对象/数组 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var token = JToken.Load(reader); // 如果是数组,直接转成List<T> if (token.Type == JTokenType.Array) { return token.ToObject<List<T>>(); } // 如果是单个对象,包装成只有一个元素的列表 return new List<T> { token.ToObject<T>() }; } // 序列化逻辑(可选):如果列表只有一个元素,转成单个对象输出 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var list = value as List<T>; if (list != null && list.Count == 1) { serializer.Serialize(writer, list[0]); } else { serializer.Serialize(writer, list); } } }
步骤2:修改实体类,给不稳定字段添加转换器
接下来修改你的实体类,把原本可能是单对象的属性改成List<T>(或者IList<T>),然后加上[JsonConverter]特性:
修改Events类的Event字段
原本的IList<Event>保留,加上转换器:
public class Events { [JsonProperty("num")] public int Num { get; set; } [JsonProperty("event")] [JsonConverter(typeof(SingleOrArrayConverter<Event>))] public IList<Event> Event { get; set; } }
修改Subtypes类的Subtype字段
注意:原来的Subtype是单个对象类型,现在要改成IList<Subtype>,因为JSON里可能是数组:
public class Subtypes { [JsonProperty("num")] public int Num { get; set; } [JsonProperty("subtype")] [JsonConverter(typeof(SingleOrArrayConverter<Subtype>))] public IList<Subtype> Subtype { get; set; } }
这样不管JSON里的event或subtype是单个对象还是数组,都能正常反序列化了!如果业务逻辑里需要取单个对象,只需要判断Subtype.Count == 1然后取Subtype[0]就行。
你需要学习的核心内容
- Json.NET自定义转换器:这是处理JSON兼容性问题的核心技能,掌握它之后大部分类型不匹配的问题都能解决。
- JSON结构分析能力:学会用JSON格式化工具快速识别哪些字段存在类型变化,提前做好兼容处理。
- C#泛型:上面的转换器用了泛型,让你不用给每个类型都写单独的转换器,大大提高代码复用性,泛型是C#里非常重要的特性。
- 可选:System.Text.Json转换器:如果你用的是.NET Core/.NET 5+自带的
System.Text.Json,它也支持自定义转换器,思路和Json.NET一致,但API略有不同,也需要了解。
内容的提问来源于stack exchange,提问作者Vladson
相关产品推荐
相关产品推荐

