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

使用TypeNameHandling.All时替换$type的Json序列化/反序列化方案

解决Json.NET序列化$type键适配Firebase的问题

问题场景

现有Car类定义:

public class Car
{
    public int Speed = 0;
}

用Json.NET开启TypeNameHandling.All序列化时:

var str = JsonConvert.SerializeObject(new Car(), new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All });

会生成带$type键的JSON:

{
    "$type":"Car",
    "Speed": 0
}

但Firebase实时数据库不允许键包含$,得把$type换成自定义键(比如typeKey),同时保证反序列化时能正常识别类型信息。

最优实现方案:自定义JsonConverter

写一个自定义转换器,双向处理类型键的替换,不破坏原有序列化逻辑:

public class FirebaseTypeConverter : JsonConverter
{
    private const string CustomTypeKey = "typeKey";
    private const string OriginalTypeKey = "$type";

    public override bool CanConvert(Type objectType)
    {
        // 适配所有需要类型标识的对象
        return true;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // 先把对象序列化到JObject
        var jObject = JObject.FromObject(value, serializer);
        // 替换$type为自定义键
        if (jObject.ContainsKey(OriginalTypeKey))
        {
            var typeValue = jObject[OriginalTypeKey];
            jObject.Remove(OriginalTypeKey);
            jObject.Add(CustomTypeKey, typeValue);
        }
        // 输出处理后的JSON
        jObject.WriteTo(writer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // 读取JSON到JObject
        var jObject = JObject.Load(reader);
        // 把自定义键换回$type,让Json.NET能识别类型
        if (jObject.ContainsKey(CustomTypeKey))
        {
            var typeValue = jObject[CustomTypeKey];
            jObject.Remove(CustomTypeKey);
            jObject.Add(OriginalTypeKey, typeValue);
        }
        // 按正常逻辑反序列化
        return jObject.ToObject(objectType, serializer);
    }
}

使用方式

序列化

把自定义转换器加入序列化配置:

var settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.All,
    Converters = new List<JsonConverter> { new FirebaseTypeConverter() }
};
var str = JsonConvert.SerializeObject(new Car(), settings);

生成的JSON就会变成符合Firebase要求的格式:

{
    "typeKey":"Car",
    "Speed": 0
}

反序列化

同样用带转换器的配置反序列化即可:

var car = JsonConvert.DeserializeObject<Car>(str, settings);

补充说明

  • 转换器会自动处理类型键的双向替换,不影响其他属性的序列化/反序列化
  • 即使是多态场景(比如父类子类的序列化)也能正常工作,因为只是替换键名,类型信息内容保持不变
  • 可以直接修改CustomTypeKey的值,换成任何符合Firebase规则的键名

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 20:03:29