Json.NET:如何使DefaultValueHandling仅适用于某些类型? [英] Json.NET: How to make DefaultValueHandling only apply to certain types?

查看:66
本文介绍了Json.NET:如何使DefaultValueHandling仅适用于某些类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义类,如下所示:

I have a custom class that looks like this:

public class PartnerLoginOptions
{
    public string Username { get; set; }
    public string Password { get; set; }
    public string DeviceModel { get; set; }
    public string Version { get; set; }

    public bool? IncludeUrls { get; set; }
    public bool? ReturnDeviceType { get; set; }
    public bool? ReturnUpdatePromptVersions { get; set; }
}

我想在序列化时忽略具有默认值的任何bool?成员,但保留具有空值的字符串.例如,如果我有一个像这样的对象

I'd like to ignore any bool? members with default values when serializing, but keep strings with null values. For example, if I had an object like this

var options = new PartnerLoginOptions
{
    Username = null,
    Password = "123",
    IncludeUrls = null,
    ReturnDeviceType = true
};

然后序列化将导致以下结果:

Then serializing would result in this:

{
    "username": null,
    "password": "123",
    "deviceModel": null,
    "version": null,
    "returnDeviceType": true
}

这是我到目前为止的代码:

Here is the code I have so far:

var settings = new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver(),
    DefaultValueHandling = DefaultValueHandling.Ignore // this applies to strings too, not just bool?
};

return JsonConvert.SerializeObject(options, settings);

是否可以通过不单独用[JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]标记每个OptionalBool属性的方式来做到这一点?谢谢.

Is there any way to do this without individually tagging each OptionalBool property with [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)]? Thanks.

推荐答案

您可以创建 DefaultContractResolver DefaultValueHandling.Ignore应用于所需类型的所有属性.但是,您的特定问题有一些限制:

You can create a custom contract resolver inheriting from DefaultContractResolver that applies DefaultValueHandling.Ignore to all properties of your required types. However, your specific question has some constraints:

  1. 您想将默认值处理应用于系统类型,即bool?.因此,无法通过将某些自定义属性应用于该类型,然后在

  1. You want to apply a default value handling to a system type, namely bool?. Thus the contract resolver cannot be implemented by applying some custom attribute to the type, then checking for it in CreateProperty(). Instead it will be necessary to pass a collection of overrides to the contract resolver's constructor.

您正在使用 CamelCasePropertyNamesContractResolver .如果将其子类化并将不同的替代列表传递给不同的实例,则会遇到来自 CamelCaseNamingStrategy >.

You are using CamelCasePropertyNamesContractResolver. If you subclass it and pass different lists of overrides to different instances, you will encounter the bug from this question that contracts are forcibly shared across all instances of each subtype, even if different instances would otherwise return different contracts. Thus it will be necessary to inherit from DefaultContractResolver, which does not have this bug, and set DefaultContractResolver.NamingStrategy to a CamelCaseNamingStrategy.

因此,您的合同解析器应如下所示:

Therefore your contract resolver should look like:

public class DefaultValueContractResolver : DefaultContractResolver
{
    readonly Dictionary<Type, DefaultValueHandling> overrides;

    public DefaultValueContractResolver(IEnumerable<KeyValuePair<Type, DefaultValueHandling>> overrides) : base()
    {
        if (overrides == null)
            throw new ArgumentNullException("overrides");
        this.overrides = overrides.ToDictionary(p => p.Key, p => p.Value);
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        if (property.DefaultValueHandling == null)
        {
            DefaultValueHandling handling;
            if (overrides.TryGetValue(property.PropertyType, out handling))
                property.DefaultValueHandling = handling;
        }

        return property;
    }
}

然后像这样使用它:

var options = new PartnerLoginOptions
{
    Username = null,
    Password = "123",
    IncludeUrls = null,
    ReturnDeviceType = true
};

var resolver = new DefaultValueContractResolver(
    new Dictionary<Type, DefaultValueHandling>
    { 
        { typeof(bool?), DefaultValueHandling.Ignore } 
    })
    {
        NamingStrategy = new CamelCaseNamingStrategy()
    };
var settings = new JsonSerializerSettings { ContractResolver = resolver };
var json = JsonConvert.SerializeObject(options, Formatting.Indented, settings);

注意:

  • 如果您有一个标准类型列表,您始终对其应用默认值处理覆盖,则应合同解析程序命名策略在Json.NET中引入了 9.0.1 .如果您使用的是较早版本并且需要驼峰式外壳,则需要子类DefaultValueContractResolver并自己添加它,例如如下:

    Contract resolver naming strategies were introduced in Json.NET 9.0.1. If you are using an earlier version and need camel casing, you will need to subclass DefaultValueContractResolver and add it yourself, e.g. as follows:

    public class DefaultValueCamelCaseContractResolver : DefaultValueContractResolver
    {
        public DefaultValueCamelCaseContractResolver(IEnumerable<KeyValuePair<Type, DefaultValueHandling>> overrides) : base(overrides) { }
    
        protected override string ResolvePropertyName(string propertyName)
        {
            return propertyName.ToCamelCase();
        }
    }
    
    public static class CamelCaseNameExtensions
    {
        class CamelCaseNameResolver : CamelCasePropertyNamesContractResolver
        {
            // Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
            static CamelCaseNameResolver() { }
            internal static readonly CamelCaseNameResolver Instance = new CamelCaseNameResolver();
    
            // Purely to make the protected method public.
            public string ToCamelCase(string propertyName)
            {
                return ResolvePropertyName(propertyName);
            }
        }
    
        public static string ToCamelCase(this string propertyName)
        {
            if (propertyName == null)
                return null;
            return CamelCaseNameResolver.Instance.ToCamelCase(propertyName);
        }
    }
    

  • 演示小提琴此处.

    这篇关于Json.NET:如何使DefaultValueHandling仅适用于某些类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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