Json.Net能否将反序列化对象转换为JSON中嵌入的类型?
解决异构类型的Json.Net反序列化问题
没问题!Json.Net(也就是Newtonsoft.Json)完全能帮你搞定这个异构类型反序列化的问题——你之前可能只是调用方式或者配置没到位,导致没自动转成嵌入的具体类型。
核心方案:正确配置TypeNameHandling并使用非泛型反序列化方法
当你用TypeNameHandling在JSON中嵌入类型信息后,不能再用带固定泛型参数的JsonConvert.DeserializeObject<Type>()(比如DeserializeObject<Animal>),因为这个泛型参数会强制反序列化为指定类型,忽略JSON里的嵌入类型信息。
正确的做法是:
- 序列化时配置
TypeNameHandling(推荐用Auto或All,根据你的场景选择) - 反序列化时调用不带泛型参数的
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
相关产品推荐
相关产品推荐

