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

如何在同一列表存储多个派生类?C# JSON反序列化场景

派生类列表存储与反序列化属性访问解决方案

完全可以在List<SubMenuVariant>中存储不同类型的派生类实例,核心是解决反序列化时的类型识别问题,以及后续访问子类专属属性的问题。由于你的列表同一时间只会包含一种子类类型,处理逻辑可以更简化。

1. 解决反序列化的类型识别问题

默认的JsonSerializer反序列化到基类时无法自动识别子类,需要通过自定义JSON转换器来根据JSON中的属性判断具体类型:

自定义JSON转换器实现

public class SubMenuVariantConverter : JsonConverter<SubMenuVariant>
{
    public override SubMenuVariant Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using var doc = JsonDocument.ParseValue(ref reader);
        var root = doc.RootElement;

        // 根据JSON中存在的专属属性判断子类类型
        if (root.TryGetProperty("SubMenuTitle", out _))
        {
            return JsonSerializer.Deserialize<SubMenuItem>(root.GetRawText(), options);
        }
        else if (root.TryGetProperty("HighlightTitle", out _))
        {
            return JsonSerializer.Deserialize<SubMenuHighlightItem>(root.GetRawText(), options);
        }

        throw new JsonException("无法识别的SubMenuVariant子类类型");
    }

    public override void Write(Utf8JsonWriter writer, SubMenuVariant value, JsonSerializerOptions options)
    {
        // 序列化时根据实例实际类型输出JSON
        JsonSerializer.Serialize(writer, value, value.GetType(), options);
    }
}

注册转换器并反序列化

var serializerOptions = new JsonSerializerOptions();
serializerOptions.Converters.Add(new SubMenuVariantConverter());

// 假设根类结构如下
public class MenuRoot
{
    public List<SubMenuVariant> submenu { get; set; }
}

// 执行反序列化
var menuRoot = JsonSerializer.Deserialize<MenuRoot>(jsonString, serializerOptions);
var submenu = menuRoot.submenu;

2. 访问子类专属属性

反序列化完成后,列表中的实例已为实际子类类型,可通过以下两种方式访问专属属性:

方式一:批量类型转换(适合列表仅含单一子类的场景)

// 转换为SubMenuItem列表
var subMenuItems = submenu.Cast<SubMenuItem>().ToList();
foreach (var item in subMenuItems)
{
    Console.WriteLine(item.SubMenuTitle);
    // 访问Link、SubItems等专属属性
}

// 转换为SubMenuHighlightItem列表
var highlightItems = submenu.Cast<SubMenuHighlightItem>().ToList();
foreach (var item in highlightItems)
{
    Console.WriteLine(item.HighlightTitle);
    // 访问HighlightText、HighLightLink等专属属性
}

方式二:模式匹配(更安全,支持混合类型场景)

foreach (var variant in submenu)
{
    if (variant is SubMenuItem menuItem)
    {
        Console.WriteLine(menuItem.SubMenuTitle);
    }
    else if (variant is SubMenuHighlightItem highlightItem)
    {
        Console.WriteLine(highlightItem.HighlightTitle);
    }
}

关键修正提示

你的SubMenuHighlightItem类存在重复的JsonPropertyName特性,会导致序列化/反序列化错误,需修正:

public class SubMenuHighlightItem : SubMenuVariant
{
    [JsonPropertyName(FieldNames.HighlightTitle)]
    public string HighlightTitle { get; set; }

    [JsonPropertyName(FieldNames.HighlightText)]
    public string HighlightText { get; set; }

    // 修正此处特性名称,匹配Link对应的字段名
    [JsonPropertyName(FieldNames.HighlightLink)]
    public Link HighLightLink { get; set; }
}

内容的提问来源于stack exchange,提问作者I am not Fat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 18:20:39