如何反序列化包含多种不同结构子类型对象数组的JSON数据
解决思路
不用定义通用泛型,通过自定义JSON转换器即可实现一次性反序列化,两种常用JSON库的实现方案如下:
方案1:基于Newtonsoft.Json实现
步骤1:补全类的属性映射
首先补全主对象的字段,同时给Parent类的属性加上与JSON字段对应的映射标记:
public class MainObject { public string id { get; set; } public string Name { get; set; } public IEnumerable<Parent> Parents { get; set; } } public class Parent { [JsonProperty("ChildName")] public string NameOfChildObjectType { get; set; } [JsonProperty("Parameters")] public object Child { get; set; } } // Child_1、Child_2、Child_3类保持原有定义即可
步骤2:定义类型映射关系
提前建立JSON中类型标识与实际CLR类型的映射字典:
internal static class ChildTypeConfig { public static readonly IReadOnlyDictionary<string, Type> Map = new Dictionary<string, Type> { {"ChildOfType1", typeof(Child_1)}, {"ChildOfType2", typeof(Child_2)}, {"ChildOfType3", typeof(Child_3)} }; }
步骤3:实现Parent类的自定义转换器
public class ParentConverter : JsonConverter<Parent> { public override Parent ReadJson(JsonReader reader, Type objectType, Parent existingValue, bool hasExistingValue, JsonSerializer serializer) { var jsonObj = JObject.Load(reader); var parent = new Parent(); // 读取类型标识 parent.NameOfChildObjectType = jsonObj["ChildName"].Value<string>(); // 匹配对应类型并反序列化Child对象 if (ChildTypeConfig.Map.TryGetValue(parent.NameOfChildObjectType, out var targetChildType)) { parent.Child = jsonObj["Parameters"].ToObject(targetChildType, serializer); } else { // 未匹配到类型时可保留原始JSON节点,或按业务需求抛出异常 parent.Child = jsonObj["Parameters"]; } return parent; } // 无需序列化能力可直接省略实现 public override void WriteJson(JsonWriter writer, Parent value, JsonSerializer serializer) => throw new NotImplementedException(); }
步骤4:直接一次性反序列化
反序列化时传入自定义转换器即可:
var deserializeSettings = new JsonSerializerSettings { Converters = { new ParentConverter() } }; var result = JsonConvert.DeserializeObject<MainObject>(yourJsonString, deserializeSettings);
方案2:基于System.Text.Json实现
逻辑与上述方案完全一致,仅需替换为System.Text.Json对应的特性与Converter基类即可,无需修改核心逻辑。
使用说明
反序列化完成后,可通过类型判断直接操作不同的Child实例:
foreach (var parent in result.Parents) { switch (parent.Child) { case Child_1 c1: // 处理Child_1类型的逻辑 break; case Child_2 c2: // 处理Child_2类型的逻辑 break; case Child_3 c3: // 处理Child_3类型的逻辑 break; } }
内容的提问来源于stack exchange,提问作者Michal Cikatricis
相关产品推荐
相关产品推荐

