Может ли 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
}
То есть, я хотел бы пропустить любые списки, коллекции, массивы или такие пустые вещи.
Ответы
Ответ 1
Если вы не нашли для этого решения, ответ замечательно прост, если вам удастся его отслеживать.
Если вам разрешено расширять исходный класс, добавьте к нему функцию ShouldSerializePropertyName
. Это должно возвращать логическое значение, указывающее, должно ли это свойство быть сериализовано для текущего экземпляра класса. В вашем примере это может выглядеть так (не проверено, но вы должны получить изображение):
public bool ShouldSerializeNumbers()
{
return _numbers.Count > 0;
}
Этот подход работает для меня (хотя и в VB.NET). Если вам не разрешено изменять исходный класс, то метод IContractResolver
, описанный на связанной странице, - это путь.
Ответ 2
Просто, чтобы быть pendantic commonorgarden, я структурировал тест if:
public bool ShouldSerializecommunicationmethods()
{
if (communicationmethods != null && communicationmethods.communicationmethod != null && communicationmethods.communicationmethod.Count > 0)
return true;
else
return false;
}
В качестве пустого списка часто также будет null. Спасибо за публикацию решения. ATB.
Ответ 3
Что касается предложения Дэвида Джонса использовать 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);
Ответ 4
Брайан, вы, скорее всего, там, где вам не нужны служебные данные переменной экземпляра, и вам нужно перехватывать оба экземпляра поля и члена, плюс я бы не стал запускать операцию подсчета, которая требует, чтобы перечислимое значение исчерпало всю коллекцию, вы можете просто запустить Функция 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;
}
}