Сериализация нулевого значения в JSON.NET

При сериализации произвольных данных через JSON.NET любое свойство, которое является null, записывается в JSON как

“propertyName”: null

Это, конечно, правильно.

Однако у меня есть требование автоматически перевести все значения null в пустую string по умолчанию, например, нулевая string s должна стать String.Empty , null int? s должно стать 0 , null bool? s должно быть false и т. д.

NullValueHandling не помогает, так как я не хочу Ignore нули, но я также не хочу Include их (Хм, новая функция?).

Поэтому я обратился к внедрению пользовательского JsonConverter .
Хотя сама реализация была ветерок, к сожалению, это все еще не сработало – CanConvert() никогда не вызывается для свойства с нулевым значением, и поэтому WriteJson() не вызывается. По-видимому, нули автоматически сериализуются непосредственно в null , без настраиваемого конвейера.

Например, здесь приведен пример пользовательского конвертера для нулевых строк:

 public class StringConverter : JsonConverter { public override bool CanConvert(Type objectType) { return typeof(string).IsAssignableFrom(objectType); } ... public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { string strValue = value as string; if (strValue == null) { writer.WriteValue(String.Empty); } else { writer.WriteValue(strValue); } } } 

Выполнив это в отладчике, я заметил, что ни один из этих методов не вызван для свойств, которые имеют нулевое значение.

Вдаваясь в исходный код JSON.NET, я обнаружил, что (по-видимому, я не вдавался в большую глубину) существует специальный случай проверки нhive и явный вызов .WriteNull() .

Для чего это стоит, я попытался реализовать пользовательский JsonTextWriter и переопределить реализацию по умолчанию .WriteNull()

 public class NullJsonWriter : JsonTextWriter { ... public override void WriteNull() { this.WriteValue(String.Empty); } } 

Однако это не сработает, поскольку метод WriteNull() ничего не знает о базовом WriteNull() данных. Поэтому я уверен, что могу вывести "" для любого нулевого значения, но это не работает хорошо, например, int, bool и т. Д.

Итак, мой вопрос – не нужно ли конвертировать всю структуру данных вручную, есть ли какое-либо решение или обходное решение для этого?

Хорошо, я думаю, что я придумал решение (мое первое решение было не совсем правильным, но потом снова я был в поезде). Вам необходимо создать специальный контрактный преобразователь и настраиваемый ValueProvider для типов Nullable. Учти это:

 public class NullableValueProvider : IValueProvider { private readonly object _defaultValue; private readonly IValueProvider _underlyingValueProvider; public NullableValueProvider(MemberInfo memberInfo, Type underlyingType) { _underlyingValueProvider = new DynamicValueProvider(memberInfo); _defaultValue = Activator.CreateInstance(underlyingType); } public void SetValue(object target, object value) { _underlyingValueProvider.SetValue(target, value); } public object GetValue(object target) { return _underlyingValueProvider.GetValue(target) ?? _defaultValue; } } public class SpecialContractResolver : DefaultContractResolver { protected override IValueProvider CreateMemberValueProvider(MemberInfo member) { if(member.MemberType == MemberTypes.Property) { var pi = (PropertyInfo) member; if (pi.PropertyType.IsGenericType && pi.PropertyType.GetGenericTypeDefinition() == typeof (Nullable<>)) { return new NullableValueProvider(member, pi.PropertyType.GetGenericArguments().First()); } } else if(member.MemberType == MemberTypes.Field) { var fi = (FieldInfo) member; if(fi.FieldType.IsGenericType && fi.FieldType.GetGenericTypeDefinition() == typeof(Nullable<>)) return new NullableValueProvider(member, fi.FieldType.GetGenericArguments().First()); } return base.CreateMemberValueProvider(member); } } 

Затем я протестировал его, используя:

 class Foo { public int? Int { get; set; } public bool? Boolean { get; set; } public int? IntField; } 

И следующий случай:

 [TestFixture] public class Tests { [Test] public void Test() { var foo = new Foo(); var settings = new JsonSerializerSettings { ContractResolver = new SpecialContractResolver() }; Assert.AreEqual( JsonConvert.SerializeObject(foo, Formatting.None, settings), "{\"IntField\":0,\"Int\":0,\"Boolean\":false}"); } } 

Надеюсь, это немного поможет …

Изменить – Лучшая идентификация типа Nullable<>

Edit – добавлена ​​поддержка полей, а также свойств, а также поддержка DynamicValueProvider поверх обычного DynamicValueProvider для выполнения большей части работы с обновленным тестом

  • GSON десериализует значение ключа для пользовательского объекта
  • Сериализация classа, который содержит std :: string
  • Сериализация jacksonа JSON, предотrotation рекурсии путем определения уровня
  • Невозможно десериализовать lambda
  • Может ли Json.NET сериализовать / десериализовать в / из streamа?
  • Json Сериализация Java, которая работает с GWT
  • XSLT: как преобразовать XML-узел в строку
  • Использование JSON.NET для возврата ActionResult
  • JSON.NET Parser * кажется * будет двойной сериализацией моих объектов
  • Исключение «Исключительная привязка к реляционной ссылке» с JSON.Net
  • Сохранение / загрузка данных в Unity
  • Interesting Posts

    Почему бы не использовать Double или Float для представления валюты?

    Несколько соединений Bluetooth

    Языки динамического типа по сравнению с языками статического типа

    Лучше ли использовать переполненный канал Wi-Fi 2,4 ГГц 1, 6, 11 или «неиспользуемый» 3, 4, 8 или 9?

    Отображать мягкую клавиатуру iPhone, даже если подключена аппаратная клавиатура

    Как сохранить удаленную задачу после запуска в консоли SSH?

    Как ограничить пропускную способность, используемую IP-адресом в поле штрафа в pfSense

    Как я могу отключить приложение?

    Невозможно изменить размер окна свойств папки.

    Проблема Webkit CSS Animation – сохранение конечного состояния анимации?

    Как создать собственный атрибут проверки для MVC

    Измените метод во время выполнения через механизм «горячей замены»

    Nlog Callsite ошибочен, когда используется обертка

    Открытие папки в проводнике и выбор файла

    Конвертировать PDF в JPG-изображения с помощью ImageMagick – как с именами файлов с 0-пэдом?

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