【问题标题】:How to omit empty collections when serializing with Json.NET使用 Json.NET 序列化时如何省略空集合
【发布时间】:2016-01-20 14:47:24
【问题描述】:

我正在使用 Newtonsoft 的 Json.NET 7.0.0.0 将 C# 中的类序列化为 JSON:

class Foo
{
    public string X;
    public List<string> Y = new List<string>();
}

var json =
    JsonConvert.SerializeObject(
        new Foo(),
        Formatting.Indented,
        new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });

这里json的值是

{ "Y": [] }

但如果 Y 是一个空列表,我希望它是 { }

我找不到令人满意的方法来实现这一目标。也许使用自定义合同解析器?

【问题讨论】:

  • 另外,我不想在集合上添加属性,因为我的类有很多属性,并且应该平等对待所有属性。
  • 而且你不能使用简单的 C# "if'?
  • @st_stefanov 如果Foo 有多个集合,但其中只有一些是空的,这将如何工作,需要解释一下吗? :)
  • 好吧,无论如何你都想序列化类,但是处理类内部的空集合...

标签: c# json json.net


【解决方案1】:

如果您正在寻找一种可以跨不同类型通用且不需要任何修改(属性等)的解决方案,那么我认为最好的解决方案是自定义 @987654321@ 类。它将使用反射来确定给定类型的任何IEnumerables 是否为空。

public class IgnoreEmptyEnumerablesResolver : DefaultContractResolver
{
    public static readonly IgnoreEmptyEnumerablesResolver Instance = new IgnoreEmptyEnumerablesResolver();

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

        if (property.PropertyType != typeof(string) &&
            typeof(IEnumerable).IsAssignableFrom(property.PropertyType))
        {
            property.ShouldSerialize = instance =>
            {
                IEnumerable enumerable = null;

                // this value could be in a public field or public property
                switch (member.MemberType)
                {
                    case MemberTypes.Property:
                        enumerable = instance
                            .GetType()
                            .GetProperty(member.Name)
                            .GetValue(instance, null) as IEnumerable;
                        break;
                    case MemberTypes.Field:
                        enumerable = instance
                            .GetType()
                            .GetField(member.Name)
                            .GetValue(instance) as IEnumerable;
                        break;
                    default:
                        break;

                }

                if (enumerable != null)
                {
                    // check to see if there is at least one item in the Enumerable
                    return enumerable.GetEnumerator().MoveNext();
                }
                else
                {
                    // if the list is null, we defer the decision to NullValueHandling
                    return true;
                }

            };
        }

        return property;
    }
}

【讨论】:

  • 谢谢,这看起来正是我需要的,不幸的是它似乎不起作用。似乎property.DeclaringType is IEnumerable 总是假的。
  • 你是对的 - 比较中有一个错误。它总是查看声明类型,而不是属性类型。我留下了一些代码,导致我的结果出现误报。现在正在修复它。
  • property.DeclaringType is IEnumerable 替换为typeof(IEnumerable).IsAssignableFrom(property.PropertyType) &amp;&amp; property.PropertyType != typeof(string),将.GetProperty(property.PropertyName).GetValue(instance, null) 替换为.GetField(property.PropertyName).GetValue(instance),然后就可以了。
  • 是的!但是您是否也希望在类的属性和字段上进行这项工作?我更新了它来处理两者。
  • 我认为enumerable 可以通过更简单的方式获得,例如property.ValueProvider?.GetValue(instance) as IEnumerable; JsonProperty 已经包装了IValueProvider,这样我们就不必使用较低级别的反射。
【解决方案2】:

如果您可以修改您的类,您可以添加 Shrink 方法并为所有空集合设置 null。它需要更改类,但它具有更好的性能。只是您的另一种选择。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-29
    • 1970-01-01
    相关资源
    最近更新 更多