有没有办法禁用DefaultValueAttributes的处理?

时间:2016-08-18 13:04:31

标签: c# json.net

我有一堆C#类,其中很多都使用DefaultValueAttribute来包含用于编辑目的的UI提示。

我正在使用Json.NET序列化这些类型的实例,并将它们发送到JavaScript客户端。为了优化带宽,我想使用DefaultValueHandling.Ignore选项,但不要考虑DefaultValueAttribute。换句话说,我只想忽略技术默认值false, 0, null,而不是开发人员定义的默认值。

原因是JavaScript客户端不知道开发人员定义的特殊默认值,因此它只能处理上面提到的一般默认值。

有没有办法关闭DefaultValueAttribute s?

2 个答案:

答案 0 :(得分:1)

您可以创建一个继承自custom contract resolverDefaultContractResolverCamelCasePropertyNamesContractResolver,将该属性的contract default value重置为default(T)

public class NoDefaultValueContractResolver : DefaultContractResolver
{
    // As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
    // http://www.newtonsoft.com/json/help/html/ContractResolver.htm
    // http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
    // "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
    static NoDefaultValueContractResolver instance;

    // Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
    static NoDefaultValueContractResolver() { instance = new NoDefaultValueContractResolver(); }

    public static NoDefaultValueContractResolver Instance { get { return instance; } }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);

        if (property.AttributeProvider.GetAttributes(typeof(DefaultValueAttribute), true).Any())
        {
            property.DefaultValue = property.PropertyType.GetDefaultValue();
        }
        return property;
    }
}

public static class TypeExtensions
{
    public static object GetDefaultValue(this Type type)
    {
        if (type == null)
            throw new ArgumentNullException("type");
        if (!type.IsValueType || Nullable.GetUnderlyingType(type) != null)
            return null;
        return Activator.CreateInstance(type, true);
    }
}

然后使用它:

var settings = new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Ignore, ContractResolver = NoDefaultValueContractResolver.Instance };
var json = JsonConvert.SerializeObject(obj, settings);

通过使用自定义合约解析程序,您可以避免为某个地方DefaultValueAttribute的某个类型或成员创建转换器。

答案 1 :(得分:0)

有趣的是Json.net使用DefaultValueAttribute - 它旨在被视觉设计表面使用,而不是序列化程序。我总是把它设置为忽略。

如果要在序列化之前应用默认值,则应在反序列化之前显式设置值;您可以在将类实例发送到序列化程序之前使用对类实例的反射来执行此操作。或者,您可以按照此处的建议,How do you modify the Json serialization of just one field using Json.net?将反射与JsonConvert结合起来,在将值写入序列化程序之前拦截该值。