我正在尝试序列化一些“懒惰创建”各种列表的遗留对象。我不能改变遗留行为。
我把它归结为这个简单的例子:
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 }
也就是说,我想跳过任何列表,集合,数组或其他空的东西。
答案 0 :(得分:66)
如果您没有找到解决方案,the answer在设法追踪时非常简单。
如果允许扩展原始类,则向其添加ShouldSerializePropertyName
函数。这应该返回一个布尔值,指示是否应该为该类的当前实例序列化该属性。在您的示例中,这可能看起来像这样(未经测试,但您应该得到图片):
public bool ShouldSerializeNumbers()
{
return _numbers.Count > 0;
}
这种方法适用于我(尽管在VB.NET中)。如果您不允许修改原始类,那么链接页面上描述的IContractResolver
方法就是您的选择。
答案 1 :(得分:3)
关于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;
}
}
然后将其构建到我的设置对象中:
static JsonSerializerSettings JsonSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
DefaultValueHandling = DefaultValueHandling.Ignore,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = ShouldSerializeContractResolver.Instance,
};
并像这样使用它:
JsonConvert.SerializeObject(someObject, JsonSettings);
答案 2 :(得分:2)
为了成为普通人,我将if测试结构化为:
public bool ShouldSerializecommunicationmethods()
{
if (communicationmethods != null && communicationmethods.communicationmethod != null && communicationmethods.communicationmethod.Count > 0)
return true;
else
return false;
}
由于空列表通常也为空。感谢您发布解决方案。 ATB。
答案 3 :(得分:2)
Bryan,您最需要的方式是不需要实例变量的开销,并且您需要捕获字段和成员实例,而且我不会运行count操作,这需要枚举来耗尽整个集合只需运行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;
}
}