c# json.net

c# - Deserializador personalizado solo para algunos campos con json.NET



(2)

Estoy tratando de deserializar algunos JSON:

{ "a":1, "b":25, "c":"1-7", "obj1":{ "a1":10, "b1":45, "c1":60 }, "obj2":[ { "a2":100, "b2":15, "c2":50 }, { "e2":"1,2,5-7", "f2":"1,3-5", "a2":25 } ] }

Quiero encontrar una forma de definir una deserialización personalizada solo para algunos campos.

En el siguiente código, separé los campos que necesitan atención (procesamiento personalizado) y los que podrían hacerse automáticamente de alguna manera.

¿Es posible deserializar automáticamente los campos "normales"? (que no necesita ningún procesamiento personalizado específico)

[JsonConverter(typeof(ConfigurationSerializer))] public class Configuration { public int a { get; set; } public int b { get; set; } public Obj1 obj1 { get; set; } public int[] c { get; set; } public IList<Obj2> obj2 { get; set; } } public class ConfigurationSerializer : JsonConverter { public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { throw new NotImplementedException(); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { JObject jsonObject = JObject.Load(reader); Configuration configuration = new Configuration(); // I would like this part to be automatic as I just repeat the default // In the real case, I have many fields here! configuration.a = (int)jsonObject["a"]; configuration.b = (int)jsonObject["b"]; configuration.obj1 = jsonObject["obj1"].ToObject<Obj1>(); // I created the JsonConverter for those 2 properties configuration.c = myCustomProcessMethod(jsonObject["c"]); configuration.obj2 = myCustomProcessMethod2(jsonObject["obj2"].ToObject<ValletConfiguration>()); return configuration; } public override bool CanConvert(Type objectType) { return typeof(Configuration).IsAssignableFrom(objectType); } }


Dado que, de todos modos, anota su tipo con atributos Json.NET, una solución más simple parecería ser poner los convertidores en las propiedades relevantes utilizando [JsonConverter(Type)] o [JsonProperty(ItemConverterType = Type)] :

public class Configuration { public int a { get; set; } public int b { get; set; } public Obj1 obj1 { get; set; } // Converts the entire list to a compressed string [JsonConverter(typeof(IntListConverter))] public int[] c { get; set; } // Converts each Obj2 item individually [JsonProperty(ItemConverterType = typeof(Obj2Converter))] public IList<Obj2> obj2 { get; set; } }

Sin embargo, si necesita conservar el convertidor en la Configuration (o está realmente agregando el convertidor a JsonSerializerSettings.Converters y no puede agregar los atributos de Json.NET a su tipo), puede usar JsonSerializer.Populate() para completar las propiedades estándar, siempre y cuando a medida que elimina por primera vez las propiedades personalizadas de JObject :

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; var jsonObject = JObject.Load(reader); var configuration = (existingValue as Configuration ?? new Configuration()); // I created the JsonConverter for those 2 properties configuration.c = myCustomProcessMethod(jsonObject["c"].RemoveFromLowestPossibleParent()); configuration.obj2 = myCustomProcessMethod2(jsonObject["obj2"].RemoveFromLowestPossibleParent().ToObject<ValletConfiguration>()); // Populate the remaining standard properties using (var subReader = jsonObject.CreateReader()) { serializer.Populate(subReader, configuration); } return configuration; }

Usando el método de extensión:

public static class JsonExtensions { public static JToken RemoveFromLowestPossibleParent(this JToken node) { if (node == null) return null; var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault(); if (contained != null) contained.Remove(); // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should if (node.Parent is JProperty) ((JProperty)node.Parent).Value = null; return node; } }


Una posible forma es crear una propiedad proxy para serializar y deserializar correctamente. Al usar ScriptIgnoreAttribute (también es posible JsonIgnoreAttribute ), la propiedad real no se serializa. Aquí hay un ejemplo:

[ScriptIgnore] public int RealProperty { get; set; } public string RealPropertyProxy { get { return SerializeRealProperty(RealProperty); } set { RealProperty = DeserializeRealProperty(value); } }

El resultado es que solo el proxy se serializa de la manera que lo definió (en función del valor de la propiedad real). Simplemente modifique las propiedades necesarias para ser serializadas de una manera especial y no necesita implementar un JsonConverter especial.