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

如何让System.Text.Json复用已有属性实现多态序列化与反序列化?

解决办法

方案1:标记基类Type属性为忽略,自动同步类型名称

修改基类的Type属性,用[JsonIgnore]标记避免序列化输出,同时让属性值自动匹配当前对象的类型名称,无需手动赋值:

public class Foo
{
    public int Id { get; set; }

    [JsonIgnore]
    public string Type 
    { 
        get => GetType().Name; 
        set { } // 空setter避免反序列化时出错
    }
}

此方案下,多态机制生成的Type鉴别器会正常输出,反序列化后对象的Type属性会自动获取正确的类型名称,无需额外处理。

方案2:自定义转换器处理重复属性

创建自定义JsonConverter,序列化时只输出一次Type属性,反序列化时忽略重复字段:

public class FooConverter : JsonConverter<Foo>
{
    public override Foo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using JsonDocument doc = JsonDocument.ParseValue(ref reader);
        JsonElement root = doc.RootElement;
        string typeName = root.GetProperty("Type").GetString()!;
        
        Type targetType = typeName switch
        {
            nameof(Foo) => typeof(Foo),
            nameof(Bar) => typeof(Bar),
            _ => throw new JsonException($"未知类型: {typeName}")
        };

        // 反序列化为目标类型
        return (Foo)JsonSerializer.Deserialize(root.GetRawText(), targetType, options)!;
    }

    public override void Write(Utf8JsonWriter writer, Foo value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        // 只写入一次Type属性,使用对象自身的Type值
        writer.WriteString("Type", value.Type);
        writer.WriteNumber("Id", value.Id);
        
        // 处理派生类的额外属性
        if (value is Bar bar)
        {
            writer.WriteString("BarSpecificProperty", bar.BarSpecificProperty);
        }
        
        writer.WriteEndObject();
    }
}

然后在序列化配置中添加转换器:

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

方案3:修改鉴别器字段名(简单但不推荐)

如果可以接受鉴别器字段名与基类属性名不同,直接修改TypeDiscriminatorPropertyName为其他名称(如$type),避免重复:

typeInfo.PolymorphismOptions = new JsonPolymorphismOptions
{
    TypeDiscriminatorPropertyName = "$type", // 使用不同名称
    DerivedTypes =
    {
        new JsonDerivedType(typeof(Foo), nameof(Foo)),
        new JsonDerivedType(typeof(Bar), nameof(Bar)),
    },
};

此方案无需修改基类,但会改变JSON结构,不符合复用已有Type属性的需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 04:35:58