Deserializzatore personalizzato solo per alcuni campi con json.NET

Sto provando a deserializzare alcuni 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 } ] } 

Voglio trovare un modo per definire una de-serializzazione personalizzata solo per alcuni campi.

Nel codice seguente, ho separato i campi che richiedono attenzione (elaborazione personalizzata) e quelli che potrebbero essere eseguiti automaticamente in qualche modo.

È ansible deserializzare automaticamente i campi “normali”? (che non richiede alcuna elaborazione personalizzata specifica)

 [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 { 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(); // I created the JsonConverter for those 2 properties configuration.c = myCustomProcessMethod(jsonObject["c"]); configuration.obj2 = myCustomProcessMethod2(jsonObject["obj2"].ToObject()); return configuration; } public override bool CanConvert(Type objectType) { return typeof(Configuration).IsAssignableFrom(objectType); } } 

Dato che stai annotando il tuo tipo con gli attributi di Json.NET, una soluzione più semplice sembrerebbe essere quella di mettere i convertitori sulle proprietà rilevanti usando [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 { get; set; } } 

Tuttavia, se è necessario conservare il convertitore in Configuration (o se si sta aggiungendo il convertitore a JsonSerializerSettings.Converters e non è ansible aggiungere attributi Json.NET al proprio tipo), è ansible utilizzare JsonSerializer.Populate() per popolare le proprietà standard, a partire da quando rimuovi per la prima volta le proprietà personalizzate dal 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()); // Populate the remaining standard properties using (var subReader = jsonObject.CreateReader()) { serializer.Populate(subReader, configuration); } return configuration; } 

Utilizzando il metodo di estensione:

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

Un modo ansible è creare una proprietà proxy per serializzare e deserializzare correttamente. Usando lo ScriptIgnoreAttribute (è ansible anche JsonIgnoreAttribute ) la proprietà reale non viene serializzata. Ecco un esempio:

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

Il risultato è che solo il proxy viene serializzato nel modo in cui è stato definito (in base al valore della proprietà reale). Basta modificare le proprietà necessarie per essere serializzate in un modo speciale e non è necessario implementare uno speciale JsonConverter .