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

Json.Net能否将反序列化对象转换为JSON中嵌入的类型?

解决异构类型的Json.Net反序列化问题

没问题!Json.Net(也就是Newtonsoft.Json)完全能帮你搞定这个异构类型反序列化的问题——你之前可能只是调用方式或者配置没到位,导致没自动转成嵌入的具体类型。

核心方案:正确配置TypeNameHandling并使用非泛型反序列化方法

当你用TypeNameHandling在JSON中嵌入类型信息后,不能再用带固定泛型参数的JsonConvert.DeserializeObject<Type>()(比如DeserializeObject<Animal>),因为这个泛型参数会强制反序列化为指定类型,忽略JSON里的嵌入类型信息。

正确的做法是:

  1. 序列化时配置TypeNameHandling(推荐用Auto或All,根据你的场景选择)
  2. 反序列化时调用不带泛型参数的JsonConvert.DeserializeObject(),或者传入object作为泛型参数,让Json.Net根据嵌入的类型信息自动实例化具体类型

示例代码:

// 定义异构类型
public class Animal {}
public class Dog : Animal { public string BarkSound { get; set; } }
public class Cat : Animal { public string MeowSound { get; set; } }

// 序列化异构对象
var serializerSettings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Auto, // 自动为非根类型或多态类型嵌入类型信息
    TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Simple // 简化类型名称
};

// 序列化Dog实例
string dogJson = JsonConvert.SerializeObject(new Dog { BarkSound = "Woof" }, serializerSettings);
// 序列化Cat实例
string catJson = JsonConvert.SerializeObject(new Cat { MeowSound = "Meow" }, serializerSettings);

// 反序列化(不需要指定具体类型)
object deserializedDog = JsonConvert.DeserializeObject(dogJson, serializerSettings);
object deserializedCat = JsonConvert.DeserializeObject(catJson, serializerSettings);

// 现在可以直接判断类型并使用强类型特性
if (deserializedDog is Dog dog)
{
    Console.WriteLine(dog.BarkSound); // 输出 "Woof"
}
if (deserializedCat is Cat cat)
{
    Console.WriteLine(cat.MeowSound); // 输出 "Meow"
}

如果你需要先获取类型再反序列化

如果你的业务场景需要提前知晓目标类型(比如做前置校验或特殊处理),也可以先从JSON中提取类型信息,再针对性反序列化:

// 解析JSON获取类型信息
JObject jsonObj = JObject.Parse(dogJson);
string typeFullName = (string)jsonObj["$type"];
// 通过反射获取Type对象
Type targetType = Type.GetType(typeFullName);

// 反序列化为指定类型
object typedObj = JsonConvert.DeserializeObject(dogJson, targetType, serializerSettings);

重要安全提示

使用TypeNameHandling时要注意反序列化漏洞:如果你的消息队列接收不可信来源的消息,恶意攻击者可能通过构造特殊的$type字段来执行恶意代码。

解决办法是配置SerializationBinder来限制允许反序列化的类型:

public class SafeTypeBinder : SerializationBinder
{
    // 白名单:只允许反序列化我们定义的类型
    private readonly HashSet<Type> _allowedTypes = new HashSet<Type>
    {
        typeof(Animal), typeof(Dog), typeof(Cat)
    };

    public override Type BindToType(string assemblyName, string typeName)
    {
        string fullTypeName = $"{typeName}, {assemblyName}";
        var targetType = _allowedTypes.FirstOrDefault(t => t.AssemblyQualifiedName == fullTypeName);
        
        if (targetType == null)
        {
            throw new InvalidOperationException($"不允许反序列化未知类型:{fullTypeName}");
        }
        return targetType;
    }
}

// 绑定到序列化配置
var safeSettings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.Auto,
    SerializationBinder = new SafeTypeBinder()
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:28:10