Json.NET:如何使DefaultValueHandling仅适用于某些类型? [英] Json.NET: How to make DefaultValueHandling only apply to certain types?
问题描述
我有一个自定义类,如下所示:
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:
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 inCreateProperty()
. 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屋!