如何在单个对象而非列表上使用Newtonsoft Json的ItemTypeNameHandling
解决方案
要让Newtonsoft.Json为单个非集合属性(如CommandTest)添加类型信息,和集合元素的处理方式一致,有以下几种直接可行的方法:
1. 为目标属性单独指定TypeNameHandling
最直接的方式是在目标属性上通过[JsonProperty]特性显式设置TypeNameHandling值,强制序列化时输出类型信息:
using Newtonsoft.Json; public interface ICommand { } public class CommandA : ICommand { } public class TestDto { // 集合默认在TypeNameHandling.Auto下会自动加类型信息 public List<ICommand> Commands { get; set; } // 为单个属性强制开启类型信息输出 [JsonProperty(TypeNameHandling = TypeNameHandling.Objects)] public ICommand CommandTest { get; set; } }
效果
序列化后,CommandTest属性会像集合中的元素一样,携带$type字段,示例输出片段:
{
"Commands": [
{"$type": "CommandA, YourAssembly", ...}
],
"CommandTest": {"$type": "CommandA, YourAssembly", ...}
}
2. 全局配置结合属性覆盖(可选)
如果全局已经设置了TypeNameHandling.Auto,但需要针对单个非多态属性强制加类型信息,同样可以用上述特性覆盖全局配置。
注意事项
- 推荐使用
TypeNameHandling.Objects只给引用类型对象添加类型信息,避免TypeNameHandling.All给所有类型(包括值类型)冗余添加$type。 - 反序列化时需注意类型注入风险,建议配合
SerializationBinder限制允许反序列化的类型,避免安全问题:var settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto, SerializationBinder = new SafeTypeBinder() }; public class SafeTypeBinder : SerializationBinder { public override Type BindToType(string assemblyName, string typeName) { // 只允许指定类型的反序列化 if (typeName == "CommandA, YourAssembly") return typeof(CommandA); throw new JsonSerializationException($"不允许的类型: {typeName}"); } }
内容的提问来源于stack exchange,提问作者ruffen
相关产品推荐
相关产品推荐

