You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将JSON反序列化为基类集合并转换为对应具体派生类实例

问题根因

System.Text.Json 默认不启用多态反序列化能力,直接指定反序列化目标为基类集合时,序列化器不会主动识别派生类型,所有集合元素都会被构造为基类实例,因此针对派生类的类型判断永远不会命中。
另外贴出的代码存在两处基础语法问题:类定义缺少class关键字、类和属性均未声明public访问修饰符,默认访问级别会导致序列化器无法正常访问成员,调试时需要先修正。

可行实现方案
  • 方案1:使用.NET 7+ 原生多态序列化配置(推荐,无第三方依赖)
    官方从.NET 7开始为System.Text.Json提供了原生多态支持,只需要在基类上标记特性配置派生类型映射即可:

    [JsonPolymorphic(TypeDiscriminatorPropertyName = "$type")]
    [JsonDerivedType(typeof(ExtendedBaseClassA), "classA")]
    [JsonDerivedType(typeof(ExtendedBaseClassB), "classB")]
    public class BaseClass // 可定义为抽象类
    {
        public int PropA { get; set; }
    }
    
    public class ExtendedBaseClassA : BaseClass
    {
        public int PropB { get; set; }
        public int PropC { get; set; }
    }
    
    public class ExtendedBaseClassB : BaseClass
    {
        public int PropD { get; set; }
        public int PropE { get; set; }
    }
    

    配置完成后,序列化时会自动在JSON中插入$type字段存储类型鉴别值,反序列化时不需要修改原有反序列化逻辑,就能自动将元素转换为对应的派生类实例。注意序列化和反序列化两端必须使用完全一致的多态配置,如果JSON字段使用小驼峰命名,只需要在JsonSerializerOptions中配置PropertyNamingPolicy = JsonNamingPolicy.CamelCase即可,不需要修改类属性定义。

  • 方案2:使用Newtonsoft.Json(Json.NET)实现
    如果项目可以引入第三方序列化库,Newtonsoft.Json默认就支持多态反序列化,只需要开启类型名称处理配置即可:
    安装对应Nuget包后,修改反序列化代码:

    IEnumerable<BaseClass> objects = JsonConvert.DeserializeObject<IEnumerable<BaseClass>>(
        serializeMessage, 
        new JsonSerializerSettings 
        {
            TypeNameHandling = TypeNameHandling.Auto
        }
    );
    

    该方案同样要求序列化时也开启TypeNameHandling.Auto配置,生成的JSON会自动携带类型元数据,反序列化时自动还原为对应派生类型。

  • 方案3:自定义类型转换器(适用于无法修改序列化输出的场景)
    如果拿到的JSON字符串本身没有携带任何类型鉴别字段,也无法调整序列化端的逻辑,可以自定义JSON转换器,根据JSON中存在的特征属性判断实际类型:

    public class BaseClassConverter : JsonConverter<BaseClass>
    {
        public override BaseClass Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            using var doc = JsonDocument.ParseValue(ref reader);
            var root = doc.RootElement;
            // 根据独有属性判断匹配的派生类型
            if (root.TryGetProperty("PropB", out _) && root.TryGetProperty("PropC", out _))
            {
                return JsonSerializer.Deserialize<ExtendedBaseClassA>(root.GetRawText(), options);
            }
            if (root.TryGetProperty("PropD", out _) && root.TryGetProperty("PropE", out _))
            {
                return JsonSerializer.Deserialize<ExtendedBaseClassB>(root.GetRawText(), options);
            }
            // 无匹配特征时兜底返回基类实例
            return JsonSerializer.Deserialize<BaseClass>(root.GetRawText(), options);
        }
    
        public override void Write(Utf8JsonWriter writer, BaseClass value, JsonSerializerOptions options)
        {
            JsonSerializer.Serialize(writer, value, value.GetType(), options);
        }
    }
    

    反序列化时将转换器加入配置即可生效:

    var options = new JsonSerializerOptions();
    options.Converters.Add(new BaseClassConverter());
    // 小驼峰配置可按需开启
    // options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
    IEnumerable<BaseClass> objects = JsonSerializer.Deserialize<IEnumerable<BaseClass>>(serializeMessage, options);
    

    这种方案不需要序列化端做任何修改,完全靠反序列化端的规则判断类型,适配性最强。

内容的提问来源于stack exchange,提问作者Guy E

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 16:24:30