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

System.Text.Json属性多态序列化不生效问题

问题根因

System.Text.Json 默认按属性的声明类型生成序列化契约,不会自动识别属性值的运行时派生类型。你的KrakenSubscribeRequest.Details属性声明为KrakenSubscriptionDetails类型,即使运行时赋值的是派生类KrakenOhlcSubscriptionDetails实例,默认序列化逻辑也只会遍历基类定义的属性,因此派生类的interval字段会丢失。
你之前写的自定义转换器本质是强制按实例运行时类型序列化,只是硬编码了单个类型,无法复用。

解决方案

方案1:通用运行时类型转换器(兼容所有.NET版本,无需修改实体类)

写一个通用的非泛型JsonConverter,不需要为每个多态基类单独实现,支持按属性粒度启用多态序列化,代码如下:

public class RuntimeTypePolymorphicConverter : JsonConverter<object>
{
    public override bool CanConvert(Type typeToConvert)
    {
        // 跳过值类型和字符串,避免干扰默认序列化逻辑
        return !typeToConvert.IsValueType && typeToConvert != typeof(string);
    }

    public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        // 仅序列化场景可直接抛出未实现异常,若需支持多态反序列化需扩展类型鉴别逻辑
        throw new NotSupportedException("多态反序列化需配合类型鉴别规则使用");
    }

    public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options)
    {
        // 强制使用实例的实际运行时类型执行序列化
        JsonSerializer.Serialize(writer, value, value.GetType(), options);
    }
}

使用方式:

  • 实现属性级多态:直接给对应属性加上转换器特性,不影响其他同类型属性的序列化逻辑
    [JsonPropertyName("subscription")]
    [JsonConverter(typeof(RuntimeTypePolymorphicConverter))]
    public KrakenSubscriptionDetails Details { get; init; }
    
  • 全局启用:将转换器加入JsonSerializerOptions.Converters集合,所有引用类型成员都会按运行时类型序列化
    var options = new JsonSerializerOptions
    {
        WriteIndented = true,
        Converters = { new RuntimeTypePolymorphicConverter() }
    };
    

注意:该方案仅适配序列化场景,反序列化时无类型标识无法自动匹配派生类,需要双向支持请使用方案2。

方案2:官方原生多态配置(.NET 7+ 支持,兼容序列化/反序列化)

你之前的配置位置有误:多态特性不需要加在根类型KrakenSubscribeRequest上,直接加在多态基类KrakenSubscriptionDetails上即可,配置完成后该基类无论作为序列化根还是其他类的属性,都会自动执行多态序列化,无需编写自定义转换器。
配置方式:给基类添加JsonDerivedType特性,注册所有需要支持的派生类

[JsonDerivedType(typeof(KrakenOhlcSubscriptionDetails))]
// 存在其他派生类时继续追加特性即可,例:[JsonDerivedType(typeof(KrakenTradeSubscriptionDetails))]
public record KrakenSubscriptionDetails
{
    // 类原有代码保持不变
}

仅做序列化使用时不需要指定类型鉴别符,运行原有测试代码即可输出包含interval字段的正确结果。
如果需要支持反序列化,给每个派生类指定唯一类型鉴别符即可,序列化时会自动写入类型标识,反序列化时可自动匹配对应派生类:

[JsonDerivedType(typeof(KrakenOhlcSubscriptionDetails), "ohlc")]

选型建议

  • 项目使用.NET 6及以下版本,或不想修改现有实体类定义:选方案1,一次编写即可在所有需要属性级多态序列化的场景复用,不需要为每个类型单独写转换器。
  • 项目使用.NET 7及以上版本,或需要支持多态反序列化:选方案2,原生实现性能更高,无需维护额外转换器逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 14:30:44