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

C#如何序列化基类列表中派生类的全部属性?

问题:序列化基类列表时保留派生类的Value属性

我需要用JsonSerializer.Serialize(...)序列化一个包含基类列表的类,但目前只有基类的属性被序列化,派生类的Value属性没有被输出。相关代码及当前问题如下:

模型定义

// ----- Models -----

public class MainClass
{
    [Key]
    public Guid Id { get; private set; } = Guid.NewGuid();
    public List<BaseClass> Properties { get; set; } = new List<BaseClass>();
}
  
public class BaseClass
{
    [Key]
    public Guid Id { get; private set; } = Guid.NewGuid();
    public string Name { get; set; } = string.Empty;
}

public class GenericDerivedClass<T> : BaseClass
{
    public T? Value { get; set; }
}

实现代码

// ----- Implementation -----

var main = new MainClass
{
    Properties = new List<BaseClass>
    {
       new GenericDerivedClass<string>
       {
           Name = "SoundFile",
           Value = "Test.wav"
       },
        new GenericDerivedClass<float>
        {
            Name = "Volume",
            Value = 1
        },
        new GenericDerivedClass<bool>
        {
            Name = "Autoplay",
            Value = false
        },
        new GenericDerivedClass<bool>
        {
            Name = "Loop",
            Value = false
        },
    }
};

Console.WriteLine(JsonSerializer.Serialize(main, new JsonSerializerOptions { WriteIndented = true }));

当前输出(缺失Value属性)

{
  "Id": "ba348c86-aa86-45ea-8d21-a9beddd4368a",        
  "Properties": [
    {
      "Id": "a9f432d5-3916-4c1d-b44a-fd4b7d8fcb45",
      "Name": "SoundFile"
      // "value": "Test.wav" <- 需要保留这个属性
    },
    {
      "Id": "f585d863-b0d7-49b3-ad5c-0565171e6793",
      "Name": "Volume"
    },
    {
      "Id": "197802f3-17cd-4c1f-90be-7ea643ee5d7d",
      "Name": "Autoplay"
    },
    {
      "Id": "b90e3857-e497-4137-adeb-94b66293d375",
      "Name": "Loop"
    }
  ]
}

需求:序列化MainClass时,让List<BaseClass>中的每个GenericDerivedClass<T>实例都输出Value属性,且不能用List<object>替代List<BaseClass>。


解决方案

方法1:使用JsonDerivedType特性(.NET 7+ 推荐)

在基类BaseClass上添加JsonDerivedType特性,指定所有需要被序列化的派生泛型具体类型:

[JsonDerivedType(typeof(GenericDerivedClass<string>), typeDiscriminator: "StringProperty")]
[JsonDerivedType(typeof(GenericDerivedClass<float>), typeDiscriminator: "FloatProperty")]
[JsonDerivedType(typeof(GenericDerivedClass<bool>), typeDiscriminator: "BoolProperty")]
public class BaseClass
{
    [Key]
    public Guid Id { get; private set; } = Guid.NewGuid();
    public string Name { get; set; } = string.Empty;
}

此时序列化会自动输出派生类的Value属性,同时默认添加类型鉴别符(如"$type": "StringProperty")。如果不需要类型鉴别符,可通过配置移除:

var options = new JsonSerializerOptions
{
    WriteIndented = true,
    TypeInfoResolver = new DefaultJsonTypeInfoResolver
    {
        Modifiers = { typeInfo =>
            {
                if (typeInfo.Type == typeof(BaseClass))
                {
                    typeInfo.PolymorphismOptions = null;
                }
            }
        }
    }
};

Console.WriteLine(JsonSerializer.Serialize(main, options));

方法2:自定义Json转换器(兼容.NET 6及以下)

如果使用旧版本.NET,可自定义转换器强制序列化实际派生类型的所有属性:

public class BaseClassConverter : JsonConverter<BaseClass>
{
    public override BaseClass? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 若需要反序列化,可补充对应逻辑
        throw new NotImplementedException();
    }

    public override void Write(Utf8JsonWriter writer, BaseClass value, JsonSerializerOptions options)
    {
        // 将基类实例转为object,让序列化器识别实际派生类型
        JsonSerializer.Serialize(writer, (object)value, options);
    }
}

序列化时添加该转换器即可:

var options = new JsonSerializerOptions
{
    WriteIndented = true,
    Converters = { new BaseClassConverter() }
};

Console.WriteLine(JsonSerializer.Serialize(main, options));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 00:39:17