您可以使用 Json.NET 的 conditional property serialization 功能完成此操作。
如果您只想在其数组值为空时忽略单个成员,请在您的类中添加一个 ShouldSerialize{PropertyName}() 方法,当您不希望它序列化时返回 false,例如:
public class RootObject
{
public string[] PostalAddress { get; set; }
public bool ShouldSerializePostalAddress() { return PostalAddress != null && PostalAddress.Length > 0; }
}
如果您需要为许多不同类型的许多不同的集合值成员执行此操作,您可以创建一个 custom contract resolver 自动为所有 then 生成一个 ShouldSerialize 谓词:
public class SkipEmptyCollectionsContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization)
.AddShouldSerializeEmptyCollections(this);
return property;
}
}
public static class JsonPropertyExtensions
{
public static JsonProperty AddShouldSerializeEmptyCollections(this JsonProperty property, IContractResolver resolver)
{
if (property == null)
throw new ArgumentNullException();
if ((typeof(IEnumerable).IsAssignableFrom(property.PropertyType) || property.PropertyType.IsAssignableFrom(typeof(IEnumerable)))
&& property.PropertyType != typeof(string)
&& property.Readable)
{
Predicate<object> shouldSerialize = (parent) =>
{
var value = property.ValueProvider.GetValue(parent);
if (value == null || value is string)
return true; // null properties are filtered by the NullValueHandling setting.
var contract = resolver.ResolveContract(value.GetType());
if (contract is JsonArrayContract)
{
return (value as IEnumerable).Any();
}
return true;
};
var oldShouldSerialize = property.ShouldSerialize;
if (oldShouldSerialize == null)
property.ShouldSerialize = shouldSerialize;
else
property.ShouldSerialize = (o) => shouldSerialize(o) && oldShouldSerialize(o);
}
return property;
}
}
public static class EnumerableExtensions
{
public static bool Any(this IEnumerable enumerable)
{
if (enumerable == null)
return false;
if (enumerable is ICollection)
{
return ((ICollection)enumerable).Count > 0;
}
var enumerator = enumerable.GetEnumerator();
using (enumerator as IDisposable)
{
return enumerator.MoveNext();
}
}
}
然后使用JsonSerializerSettings 进行序列化,如下所示,这也启用了名称的驼峰式大小写:
var settings = new JsonSerializerSettings
{
ContractResolver = new SkipEmptyCollectionsContractResolver { NamingStrategy = new CamelCaseNamingStrategy() },
NullValueHandling = NullValueHandling.Ignore,
};
如果您想使用属性有条件地过滤掉空集合,您可以使用以下合约解析器和属性来实现:
public enum EmptyArrayHandling
{
Include = 0,
Ignore = 1,
}
[System.AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class JsonPropertyExtensionsAttribute : System.Attribute
{
public EmptyArrayHandling EmptyArrayHandling { get; set; }
}
public class ConditionallySkipEmptyCollectionsContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
var attr = property.AttributeProvider.GetAttributes(typeof(JsonPropertyExtensionsAttribute), false).Cast<JsonPropertyExtensionsAttribute>().FirstOrDefault();
if (attr != null && attr.EmptyArrayHandling == EmptyArrayHandling.Ignore)
property = property.AddShouldSerializeEmptyCollections(this);
return property;
}
}
然后按以下方式向您的会员申请:
public class RootObject
{
[JsonPropertyExtensions(EmptyArrayHandling = EmptyArrayHandling.Ignore)]
public string[] PostalAddress { get; set; }
}
请注意,如果您的“集合”实际上是一个复杂的 LINQ 查询,ShouldSerialize 方法将不得不枚举查询的第一个元素以查看它是否为空,这可能会导致性能不佳,因为查询会得到评价了两次。为避免这种情况,您可以在序列化之前将整个查询评估为一个列表。
您可能需要cache the contract resolver 以获得最佳性能。