Как пропустить / игнорировать / пропускать пустые литералы объектов в выпуске JSON?

Я использую Json.NET для преобразования сложного графа объектов C# в JSON. Из-за игнорирования свойств, которые имеют значения по умолчанию в объекте, я обычно получаю пустые литералы объектов на выходе, которые я бы хотел опустить.

Например:

 public class Sample { public int Value { get; set; } public string Name { get; set; } } public class ParentSample { // this property should never be null, hence the initializer public Sample Sample { get; } = new Sample(); } .. var obj = new ParentSample(); // settings for indentation and excluding default values omitted for clarity var output = JsonConvert.SerializeObject(obj, ... ); // output will be // { // Sample: {} // } // // I'd like it to be // {} 

Я знаю некоторые конкретные решения, такие как добавление булевского метода ShouldSerializeSample к типу ParentSample и проверка наличия по умолчанию всех свойств. Однако я хотел бы получить общее решение в виде пользовательского адаптера контракта, например.

В комментариях похоже, что вы решили прибегнуть к использованию Regex, чтобы избавиться от пустых объектов. Одна из проблем с этой идеей заключается в том, что она, вероятно, не будет обрабатывать ситуацию, когда у вас есть то, что я назову «рекурсивные пустые объекты». Другими словами, что-то вроде этого:

 { "foo": { "bar": {}, "baz": {} } } 

Если вам удастся выровнять bar с пустым объектом с самым высоким уровнем и baz с помощью Regex (хотя вы также понимаете, что вам нужно удалить запятую между ними, чтобы JSON был действителен), вы все равно оставите пустой объект: foo .

 { "foo": { } } 

Я считаю, что лучшим решением является загрузка ваших данных в иерархию JToken а затем использование рекурсивного метода для удаления всех пустых детей, прежде чем записывать их в JSON. Что-то вроде этого должно работать для ваших нужд:

 using System; using Newtonsoft.Json.Linq; public static class JsonHelper { public static string SerializeToMinimalJson(object obj) { return JToken.FromObject(obj).RemoveEmptyChildren().ToString(); } public static JToken RemoveEmptyChildren(this JToken token) { if (token.Type == JTokenType.Object) { JObject copy = new JObject(); foreach (JProperty prop in token.Children()) { JToken child = prop.Value; if (child.HasValues) { child = child.RemoveEmptyChildren(); } if (!child.IsEmptyOrDefault()) { copy.Add(prop.Name, child); } } return copy; } else if (token.Type == JTokenType.Array) { JArray copy = new JArray(); foreach (JToken item in token.Children()) { JToken child = item; if (child.HasValues) { child = child.RemoveEmptyChildren(); } if (!child.IsEmptyOrDefault()) { copy.Add(child); } } return copy; } return token; } public static bool IsEmptyOrDefault(this JToken token) { return (token.Type == JTokenType.Array && !token.HasValues) || (token.Type == JTokenType.Object && !token.HasValues) || (token.Type == JTokenType.String && token.ToString() == String.Empty) || (token.Type == JTokenType.Boolean && token.Value() == false) || (token.Type == JTokenType.Integer && token.Value() == 0) || (token.Type == JTokenType.Float && token.Value() == 0.0) || (token.Type == JTokenType.Null); } } 

Затем вы можете сериализовать свой объект (ы) следующим образом:

 var json = JsonHelper.SerializeToMinimalJson(obj); 

Сценарий: https://dotnetfiddle.net/awRPMR

РЕДАКТИРОВАТЬ

Если вы хотите почитать [DefaultValue] этим методом, вы можете сделать это, изменив метод SerializeToMinimalJson() чтобы создать экземпляр JsonSerializer , установив на DefaultValueHandling свойство DefaultValueHandling , а затем передав его в JToken.FromObject() как показано ниже. (Это нужно сделать так, потому что у JTokens нет ссылок на исходные объекты, из которых они были созданы с помощью FromObject() , поэтому после этого невозможно получить значения атрибутов [DefaultValue] .)

 public static string SerializeToMinimalJson(object obj) { var serializer = new JsonSerializer(); serializer.NullValueHandling = NullValueHandling.Ignore; serializer.DefaultValueHandling = DefaultValueHandling.Ignore; return JToken.FromObject(obj, serializer).RemoveEmptyChildren().ToString(); } 

Если вы это сделаете, вы также можете изменить метод IsEmptyOrDefault() чтобы он не IsEmptyOrDefault() значения, которые являются стандартными по умолчанию. Вы можете уменьшить его до:

 public static bool IsEmptyOrDefault(this JToken token) { return (token.Type == JTokenType.Array && !token.HasValues) || (token.Type == JTokenType.Object && !token.HasValues); } 

Сценарий: https://dotnetfiddle.net/0yVRI5

Вы можете дать JsonSerializerSettings для метода, используя NullValueHandling.Ignore :

 var output = JsonConvert.SerializeObject(obj, new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }); 

Если эти настройки не дают то, что вам нужно, проверьте: документацию. Там вы найдете все свойства и описание.

Изменить: использование дочернего элемента (Sample) в качестве структуры работает с DefaultValueHandling.Ignore. Но @ Zoltán Tamási будет использовать регулярное выражение из-за сложности classа.

Я внедрил немного другое решение, которое использует общий метод, reflection и некоторую стандартную функциональность Newtonsoft.Json ShouldSerialize. Не элегантный, но концептуально простой для моей конкретной потребности. Ниже приведен fragment кода LinqPad.

 void Main() { Person person = new Person(); person.MyAddress = new Address(); var ret = person.ShouldSerializeMyAddress(); var json = JsonConvert.SerializeObject(person, Newtonsoft.Json.Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); json.Dump(); } public static class JsonExtensions { public static bool ShouldSerialize(this object self) { if (self == null) return false; var methods = self.GetType().GetMethods().Where(p => p.Name.StartsWith("ShouldSerialize")); return methods.Any(p => p.Invoke(self, null) is bool value && value); } } public class Person { public Address MyAddress { get; set; } public bool ShouldSerializeMyAddress() { return MyAddress.ShouldSerialize(); } } public class Address { public string Street { get; set; } public bool ShouldSerializeStreet() { return false; // or whatever your property serialization criteria should be } public string City { get; set; } public bool ShouldSerializeCity() { return false; } public string State { get; set; } public bool ShouldSerializeState() { return false; } public string Zip { get; set; } public bool ShouldSerializeZip() { return false; } } 
  • Json.Net: свойство Serialize / Deserialize в качестве значения, а не как объект
  • Игнорирование нулевых полей в Json.net
  • JSON.net: как десериализовать без использования конструктора по умолчанию?
  • Удаление десериализации JSON в .NET-объект с использованием Newtonsoft (или LINQ to JSON, возможно?)
  • Как десериализовать данные JSON?
  • Преобразовать Newtonsoft.Json.Linq.JArray в список определенного типа объекта
  • Поиск конкретного JToken по имени в иерархии JObject
  • JSON.Net: принудительная сериализация всех частных полей и всех полей в подclassах
  • Создайте строго типизированный объект c # из объекта json с ID как имя
  • Как создать JSON.NET Date to String custom Converter
  • Как обрабатывать как отдельный элемент, так и массив для одного и того же свойства с помощью JSON.net
  • Interesting Posts

    Ориентация в UIView добавлена ​​в UIWindow

    Bootstrap: как складывать divs разной высоты?

    Какую файловую систему следует использовать между OSX и Linux

    Как настроить таргетинг на определенную версию iPhone?

    Лучшая практика использования $ rootcope в приложении Angularjs?

    Как сохранить выделенный текст при изменении фокуса в Microsoft Word / Excel

    Передвижные кнопки и проводники Windows Explorer

    Совместная сессия между двумя веб-сайтами с использованием asp.net и государственного сервера

    Что не так с моим HDD?

    Как отображать активность, когда экран заблокирован?

    Назначение портов TCP / IP для внутреннего использования приложений

    Android Studio 0.4 Дублирующие файлы, скопированные в APK META-INF / LICENSE.txt

    Обработка скобок при преобразовании инфиксных выражений в постфиксные выражения

    Затухание в каждом элементе – один за другим

    Проверьте, присутствует ли SDCard, логическое значение всегда верно

    Давайте будем гением компьютера.