c# .net serialization json.net

c# - Serializar null en JSON.NET



serialization (1)

De acuerdo, creo que he encontrado una solución (mi primera solución no fue para nada, pero de nuevo estaba en el tren). Debe crear una resolución de contrato especial y un ValueProvider personalizado para tipos anulables. Considera esto:

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); } }

Luego lo probé usando:

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

Y el siguiente caso:

[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}"); } }

Espero que esto ayude un poco ...

Editar - Mejor identificación del tipo Nullable<>

Editar - Se agregó soporte para campos y propiedades, también respaldo en la parte superior del DynamicValueProvider normal para hacer la mayor parte del trabajo, con la prueba actualizada

Al serializar datos arbitrarios a través de JSON.NET, cualquier propiedad que sea nula se escribe en el JSON como

"propertyName": null

Esto es correcto, por supuesto.

Sin embargo, tengo un requisito para traducir automáticamente todos los nulos en el valor vacío predeterminado, por ejemplo, la string nula s debe convertirse en String.Empty , null int? s debería convertirse en 0 , null bool? s debe ser false , y así sucesivamente.

NullValueHandling no es útil, ya que no quiero Ignore nulos, pero tampoco quiero Include (Hmm, ¿nueva función?).

Así que JsonConverter a la implementación de un JsonConverter personalizado.
Si bien la implementación en sí misma fue muy fácil, lamentablemente esto aún no funcionó: nunca se llama a CanConvert() para una propiedad que tiene un valor nulo, y por WriteJson() tanto WriteJson() se llama a WriteJson() . Aparentemente, los nulos se serializan automáticamente directamente en null , sin la interconexión personalizada.

Por ejemplo, aquí hay una muestra de un convertidor personalizado para cadenas nulas:

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); } } }

Pasando por esto en el depurador, noté que ninguno de estos métodos se llama para las propiedades que tienen un valor nulo.

Profundizando en el código fuente de JSON.NET, encontré que (aparentemente, no profundicé mucho) hay un caso especial que verifica los nulos y llama .WriteNull() a .WriteNull() .

Por lo que vale, intenté implementar un JsonTextWriter personalizado y anulando la implementación .WriteNull() predeterminada ...

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

Sin embargo, esto no puede funcionar bien, ya que el método WriteNull() no sabe nada sobre el tipo de datos subyacente. Así que estoy seguro de que puedo enviar "" para cualquier nulo, pero eso no funciona bien, por ejemplo, int, bool, etc.

Por lo tanto, mi pregunta, además de convertir toda la estructura de datos manualmente, ¿hay alguna solución o solución para esto?