Newtonsoft Json.NET可以跳过序列化空列表吗?

Phi*_*ell 54 c# serialization list json.net

我试图序列化一些"懒惰创建"各种列表的遗留对象.我无法改变遗留行为.

我把它归结为这个简单的例子:

public class Junk
{
    protected int _id;

    [JsonProperty( PropertyName = "Identity" )]
    public int ID 
    { 
        get
        {
            return _id;
        }

        set
        {
            _id = value;
        }
    }

    protected List<int> _numbers;
    public List<int> Numbers
    {
        get
        {
            if( null == _numbers )
            {
                _numbers = new List<int>( );
            }

            return _numbers;
        }

        set
        {
            _numbers = value;
        }
    }
}

class Program
{
    static void Main( string[] args )
    {
        Junk j = new Junk( ) { ID = 123 };

        string newtonSoftJson = JsonConvert.SerializeObject( j, Newtonsoft.Json.Formatting.Indented );

        Console.WriteLine( newtonSoftJson );

    }
}
Run Code Online (Sandbox Code Playgroud)

目前的结果是:{"身份":123,"数字":[]}

我想得到:{"身份":123}

也就是说,我想跳过任何列表,集合,数组或其他空的东西.

Dav*_*ull 73

如果您没有找到解决方案,那么当您设法跟踪它时,答案非常简单.

如果允许扩展原始类,则向其添加一个ShouldSerializePropertyName函数.这应该返回一个布尔值,指示是否应该为该类的当前实例序列化该属性.在您的示例中,这可能看起来像这样(未经测试,但您应该得到图片):

public bool ShouldSerializeNumbers()
{
    return _numbers.Count > 0;
}
Run Code Online (Sandbox Code Playgroud)

这种方法适用于我(尽管在VB.NET中).如果您不允许修改原始类,则IContractResolver链接页面上描述的方法是可行的方法.

  • 我可以通用的方式吗?我不知道所有属性名称,但希望所有空数组都为null. (5认同)

Buv*_*uvy 7

布莱恩,你是最不需要实例变量的开销的方式,你需要捕获字段和成员实例,而且我不会运行计数操作,这需要枚举来耗尽整个集合,你可以简单地运行MoveNext() 函数。

public class IgnoreEmptyEnumerableResolver : CamelCasePropertyNamesContractResolver
{
    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;
                }

                return enumerable == null ||
                       enumerable.GetEnumerator().MoveNext();
                // if the list is null, we defer the decision to NullValueHandling
            };
        }

        return property;
    }
}
Run Code Online (Sandbox Code Playgroud)


J B*_*ice 6

关于David Jones的使用建议IContractResolver,这对我来说可以覆盖所有IEnumerables变体而无需显式修改需要序列化的类:

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

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

        if (property.PropertyType.GetInterface(nameof(IEnumerable)) != null)
            property.ShouldSerialize =
                instance => (instance?.GetType().GetProperty(property.PropertyName).GetValue(instance) as IEnumerable<object>)?.Count() > 0;

        return property;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将其构建到我的设置对象中:

static JsonSerializerSettings JsonSettings = new JsonSerializerSettings
{
    Formatting = Formatting.Indented,
    NullValueHandling = NullValueHandling.Ignore,
    DefaultValueHandling = DefaultValueHandling.Ignore,
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
    ContractResolver = ShouldSerializeContractResolver.Instance,
};
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

JsonConvert.SerializeObject(someObject, JsonSettings);
Run Code Online (Sandbox Code Playgroud)

  • 我必须将行 `instance =&gt; (instance?.GetType().GetProperty(property.PropertyName).GetValue(instance) as IEnumerable&lt;object&gt;)?.Count() &gt; 0;` 更改为 `instance =&gt; ( instance?.GetType().GetProperty(property.PropertyName)?.GetValue(instance) as IEnumerable)?.OfType&lt;object&gt;().Count() &gt; 0;` 否则,非空 IEnumerables 中的对象将被序列化为“{ }” (3认同)
  • 如果您使用命名策略,您应该使用“GetProperty(property.UnderlyingName)”而不是“GetProperty(property.PropertyName)”。 (2认同)