Newtonsoft 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 );


}
}

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

我想得到: { “身份”: 123 }

也就是说,我希望跳过任何列表、集合、数组或其他空的内容。

43370 次浏览

如果您没有找到这个问题的解决方案,那么当您设法跟踪它时,答案非常简单。

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

public bool ShouldSerializeNumbers()
{
return _numbers.Count > 0;
}

这种方法对我很有用(尽管是在 VB.NET 中)。如果不允许修改原始类,那么可以采用链接页面上描述的 IContractResolver方法。

为了成为一个悬垂的普通花园,我设计了 if 测试:

public bool ShouldSerializecommunicationmethods()
{
if (communicationmethods != null && communicationmethods.communicationmethod != null && communicationmethods.communicationmethod.Count > 0)
return true;
else
return false;
}

作为一个空列表往往也是空的。感谢张贴解决方案。

关于 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 != typeof(string)) {
if (property.PropertyType.GetInterface(nameof(IEnumerable)) != null)
property.ShouldSerialize =
instance => (instance?.GetType().GetProperty(property.PropertyName).GetValue(instance) as IEnumerable<object>)?.Count() > 0;
}
return property;
}
}

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

static JsonSerializerSettings JsonSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = ShouldSerializeContractResolver.Instance,
};

像这样使用它:

JsonConvert.SerializeObject(someObject, JsonSettings);

布莱恩你是最不需要开销的实例变量,你需要捕获两个字段和成员实例加上我不会运行计数操作,这需要枚举穷尽整个集合你可以简单地运行 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;
}
}