13

我有一个包含多个属性的对象,这些属性是字符串列表List<String>或字符串字典Dictionary<string,string>。我想使用 Json.net 将对象序列化为 json,并且希望生成最少的文本。

我正在使用 DefaultValueHandling 和 NullValueHandling 将默认值设置为字符串和整数。但是,如果将 DefaultValueHandling 初始化为空List<String>或,如何定义 DefaultValueHandling 以忽略序列化输出中的属性Dictionary<string,string>

一些示例输出是:

{
 "Value1": "my value",
 "Value2": 3,
 "List1": [],
 "List2": []
}

我想得到一个忽略上面示例中的两个列表的结果,因为它们被设置为空列表的默认值。

任何帮助将不胜感激

4

2 回答 2

19

我已经在我的个人框架的自定义合同解析器中实现了这个功能(链接到特定的提交,以防文件稍后移动)。它使用一些辅助方法并包含一些用于自定义引用语法的无关代码。没有它们,代码将是:

public class SkipEmptyContractResolver : DefaultContractResolver
{
    public SkipEmptyContractResolver (bool shareCache = false) : base(shareCache) { }

    protected override JsonProperty CreateProperty (MemberInfo member,
            MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);
        bool isDefaultValueIgnored =
            ((property.DefaultValueHandling ?? DefaultValueHandling.Ignore)
                & DefaultValueHandling.Ignore) != 0;
        if (isDefaultValueIgnored
                && !typeof(string).IsAssignableFrom(property.PropertyType)
                && typeof(IEnumerable).IsAssignableFrom(property.PropertyType)) {
            Predicate<object> newShouldSerialize = obj => {
                var collection = property.ValueProvider.GetValue(obj) as ICollection;
                return collection == null || collection.Count != 0;
            };
            Predicate<object> oldShouldSerialize = property.ShouldSerialize;
            property.ShouldSerialize = oldShouldSerialize != null
                ? o => oldShouldSerialize(o) && newShouldSerialize(o)
                : newShouldSerialize;
        }
        return property;
    }
}

此合同解析器将跳过所有空集合(所有类型实现ICollection和具有Length == 0)的序列化,除非DefaultValueHandling.Include为属性或字段指定。

于 2013-08-28T11:37:10.210 回答
10

另一个非常简单的解决方案是在此处ShouldSerialize*将被序列化为大纲的类型中实现一个方法。

如果您可以控制被序列化的类型并且它不是您想要引入的一般行为,这可能是首选方式。

于 2015-11-09T13:50:16.580 回答