求助:JSON.net NewtonSoft无法正确转换字典中的继承对象
用JSON.net序列化/反序列化字典中的继承对象
嘿,我之前也踩过这个坑——JSON.net默认序列化继承对象时不会保留具体类型信息,导致反序列化后字典里的B、C都会变成基类A的实例。给你分享个实用的解决办法:
核心思路:开启类型信息追踪
JSON.net提供了TypeNameHandling配置项,能让序列化后的JSON带上对象的具体类型标识,这样反序列化时就能精准还原成原本的子类实例。
1. 序列化字典
先创建你的字典实例,然后配置序列化选项:
// 初始化字典 var myDict = new Dictionary<string, A> { { "BInstance", new B() }, { "CInstance", new C() } }; // 配置JSON序列化设置 var serializeSettings = new JsonSerializerSettings { // Auto模式只会在类型与声明类型不一致时添加类型信息,更高效 TypeNameHandling = TypeNameHandling.Auto, Formatting = Formatting.Indented // 可选,让JSON格式更易读 }; // 序列化 string jsonResult = JsonConvert.SerializeObject(myDict, serializeSettings);
生成的JSON会包含$type字段,比如:
{ "BInstance": { "$type": "YourProjectNamespace.B, YourProjectAssembly", "Score": 5, "Value": "5" }, "CInstance": { "$type": "YourProjectNamespace.C, YourProjectAssembly", "AnotherScore": 6, "Value": "6" } }
2. 反序列化字典
反序列化时必须使用相同的配置,才能识别$type字段还原子类:
// 用同样的设置反序列化 var deserializedDict = JsonConvert.DeserializeObject<Dictionary<string, A>>(jsonResult, serializeSettings); // 测试一下:deserializedDict["BInstance"] 现在是B类型,不是A if (deserializedDict["BInstance"] is B bObj) { Console.WriteLine(bObj.Score); // 会输出5 }
3. 安全注意事项(重要!)
如果你的JSON来自不可信来源,直接用TypeNameHandling可能存在反序列化注入风险。这种情况下,要配合SerializationBinder限制允许的类型:
public class RestrictedTypeBinder : SerializationBinder { public override Type BindToType(string assemblyName, string typeName) { // 只允许我们自己定义的A、B、C类型 var allowedTypes = new List<Type> { typeof(A), typeof(B), typeof(C) }; var targetType = allowedTypes.FirstOrDefault(t => t.FullName == typeName); if (targetType == null) { throw new JsonSerializationException($"不允许反序列化类型:{typeName}"); } return targetType; } }
然后把这个绑定器加到序列化设置里:
serializeSettings.SerializationBinder = new RestrictedTypeBinder();
这样既解决了类型还原的问题,又保证了安全性。
内容的提问来源于stack exchange,提问作者Joas
相关产品推荐
相关产品推荐

