json.net - 如何仅在根对象上添加属性 $type [英] json.net - how to add property $type ONLY on root object

查看:13
本文介绍了json.net - 如何仅在根对象上添加属性 $type的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想修改我的 json.NET 序列化程序,只将 $type 属性添加到实现给定接口的对象,而不是任何属性或嵌套对象.

使用 TypeNameHandling.Auto(默认)

<代码>{属性A":123,"PropertyB": "foo",属性 C":[1、2、3、4]}

使用 TypeNameHandling.All

<代码>{"$type": "JsonNetTypeNameHandling.TestEvent, jsonNetTypeNameHandling",属性A":123,"PropertyB": "foo",属性C":{"$type": "System.Collections.Generic.List`1[[System.Int32, mscorlib]], mscorlib","$values": [1, 2, 3, 4]}}

我想要什么

<代码>{"$type": "JsonNetTypeNameHandling.TestEvent, jsonNetTypeNameHandling",属性A":123,"PropertyB": "foo",属性 C":[1、2、3、4]}

我正在尝试使用自定义 ContractResolver,但无法正常工作:

类程序{静态无效主要(字符串 [] 参数){var serializerSettings = new JsonSerializerSettings(){TypeNameHandling = TypeNameHandling.Auto,TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,ContractResolver = new EnableTypeNameHandlingAllOnlyForEvents(),格式 = 格式.缩进};var event1 = new TestEvent() { PropertyA = 123, PropertyB = "foo", PropertyC = new List;{ 1, 2, 3, 4 } };字符串 event1Serialized = JsonConvert.SerializeObject(event1, serializerSettings);Console.WriteLine(event1Serialized);Console.ReadLine();}}公共接口 IEvent{}公共类TestEvent:IEvent{公共 int PropertyA { 获取;放;}公共字符串 PropertyB { 获取;放;}公共列表<int>属性C { 得到;放;}}公共类 EnableTypeNameHandlingAllOnlyForEvents : DefaultContractResolver{受保护的覆盖 JsonObjectContract CreateObjectContract(Type objectType){var x = base.CreateObjectContract(objectType);if (typeof(IEvent).IsAssignableFrom(x.UnderlyingType)){//如何告诉 json.NET 将 $type 添加到此 (IEvent) 类型的实例中???}返回 x;}}

解决方案

如果您需要根对象的 "$type" 属性,并且可以将其显示在嵌套的多态对象和数组中如果需要,请将以下重载与 TypeNameHandling.Auto 一起使用:JsonConvert.SerializeObject(Object, Type, JsonSerializerSettings).

来自 文档:

<块引用>

公共静态字符串 SerializeObject(对象值,类型类型,JsonSerializerSettings 设置)

类型类型:System.Type被序列化的值的类型.当 TypeNameHandling 为 Auto 时使用此参数,如果值的类型不匹配,则写出类型名称.指定类型是可选的.

即,做:

var serializerSettings = new JsonSerializerSettings(){TypeNameHandling = TypeNameHandling.Auto,TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,格式 = 格式.缩进};var event1Serialized = JsonConvert.SerializeObject(event1, typeof(IEvent), serializerSettings);

如果您在根对象上需要 "$type" 并且在嵌套的多态对象和数组上接受它,即使另有要求,您将需要使用TypeNameHandling.All 以及 自定义合约解析器 设置 JsonContainerContract.ItemTypeNameHandling = TypeNameHandling.None:

公共类 SuppressItemTypeNameContractResolver : DefaultContractResolver{受保护的覆盖 JsonContract CreateContract(Type objectType){var contract = base.CreateContract(objectType);var containerContract = 合同为 JsonContainerContract;if (containerContract != null){if (containerContract.ItemTypeNameHandling == null)containerContract.ItemTypeNameHandling = TypeNameHandling.None;}退货合同;}}

然后像这样使用它:

静态 IContractResolver suppressItemTypeNameContractResolver = new SuppressItemTypeNameContractResolver();var serializerSettings = new JsonSerializerSettings(){TypeNameHandling = TypeNameHandling.All,ContractResolver = suppressItemTypeNameContractResolver,//根据需要进行其他设置.TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,格式 = 格式.缩进};var event1Serialized = JsonConvert.SerializeObject(event1, serializerSettings);

注意事项:

I want to modify my json.NET serializer to add the $type property only to the objects which implements a given interface but not to any property or nested objects.

With TypeNameHandling.Auto (default)

{
  "PropertyA": 123,
  "PropertyB": "foo",
  "PropertyC": [1, 2, 3, 4]
}

With TypeNameHandling.All

{
  "$type": "JsonNetTypeNameHandling.TestEvent, jsonNetTypeNameHandling",
  "PropertyA": 123,
  "PropertyB": "foo",
  "PropertyC": {
    "$type": "System.Collections.Generic.List`1[[System.Int32, mscorlib]], mscorlib",
    "$values": [1, 2, 3, 4 ]
  }
}

What I want

{
  "$type": "JsonNetTypeNameHandling.TestEvent, jsonNetTypeNameHandling",
  "PropertyA": 123,
  "PropertyB": "foo",
  "PropertyC": [1, 2, 3, 4]
}

I am experimenting with a custom ContractResolver but I don't get it to work:

class Program
{
    static void Main(string[] args)
    {
        var serializerSettings = new JsonSerializerSettings()
        {
            TypeNameHandling = TypeNameHandling.Auto,
            TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,
            NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
            ContractResolver = new EnableTypeNameHandlingAllOnlyForEvents(),
            Formatting = Formatting.Indented
        };

        var event1 = new TestEvent() { PropertyA = 123, PropertyB = "foo", PropertyC = new List<int> { 1, 2, 3, 4 } };

        string event1Serialized = JsonConvert.SerializeObject(event1, serializerSettings);

        Console.WriteLine(event1Serialized);
        Console.ReadLine();
    }
}

public interface IEvent
{
}

public class TestEvent : IEvent
{
    public int PropertyA { get; set; }
    public string PropertyB { get; set; }
    public List<int> PropertyC { get; set; }
}

public class EnableTypeNameHandlingAllOnlyForEvents : DefaultContractResolver
{
    protected override JsonObjectContract CreateObjectContract(Type objectType)
    {
        var x = base.CreateObjectContract(objectType);

        if (typeof(IEvent).IsAssignableFrom(x.UnderlyingType))
        {
            // What to do to tell json.NET to add $type to instances of this (IEvent) type???
        }

        return x;
    }
}

解决方案

If you require the "$type" property on your root object and are OK with it appearing on nested polymorphic objects and arrays if required, use the following overload along with TypeNameHandling.Auto: JsonConvert.SerializeObject(Object, Type, JsonSerializerSettings).

From the docs:

public static string SerializeObject(
    Object value,
    Type type,
    JsonSerializerSettings settings
)

type Type: System.Type The type of the value being serialized. This parameter is used when TypeNameHandling is Auto to write out the type name if the type of the value does not match. Specifing the type is optional.

I.e., do:

var serializerSettings = new JsonSerializerSettings()
{
    TypeNameHandling = TypeNameHandling.Auto,
    TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
    Formatting = Formatting.Indented
};

var event1Serialized = JsonConvert.SerializeObject(event1, typeof(IEvent), serializerSettings);

If you require "$type" on the root object and will not accept it on nested polymorphic objects and arrays even if otherwise required, you will need to use TypeNameHandling.All along with a custom contract resolver that sets JsonContainerContract.ItemTypeNameHandling = TypeNameHandling.None:

public class SuppressItemTypeNameContractResolver : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        var contract = base.CreateContract(objectType);
        var containerContract = contract as JsonContainerContract;
        if (containerContract != null)
        {
            if (containerContract.ItemTypeNameHandling == null)
                containerContract.ItemTypeNameHandling = TypeNameHandling.None; 
        }
        return contract;
    }
}

Then use it like:

static IContractResolver suppressItemTypeNameContractResolver = new SuppressItemTypeNameContractResolver();

var serializerSettings = new JsonSerializerSettings()
{
    TypeNameHandling = TypeNameHandling.All,
    ContractResolver = suppressItemTypeNameContractResolver,
    // Other settings as required.
    TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
    Formatting = Formatting.Indented
};
var event1Serialized = JsonConvert.SerializeObject(event1, serializerSettings);

Notes:

这篇关于json.net - 如何仅在根对象上添加属性 $type的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆