2016-05-01 13 views
9

ich auf einen Dienst gestolpert, die JSON in folgendem Format ausgibt:Json.NET Benutzerdefinierte JsonConverter mit Datentypen

{ 
    "Author": "me", 
    "Version": "1.0.0", 
    "data.Type1": { 
     "Children": [ 
      { 
       "data.Type1": { 
        "Children": [ 
         { 
          "data.Type2": { 
           "name": "John", 
           "surname": "Doe" 
          } 
         } 
        ] 
       } 
      }, 
      { 
       "data.Type3": { 
        "dob": "1990-01-01" 
       } 
      } 
     ] 
    } 
} 

Typ Datennamen als Eigenschaftsnamen erhalten bleiben und ihre Werte sind die eigentlichen Objekte. Sie beginnen alle mit einem data. Präfix.

{ // Root 
    "Author": "me", 
    "Version": "1.0.0", 
    "Children": [ // Type1 
     { 
      "Children": [ // Type1 
       { // Type2 
        "Name": "John", 
        "Surname": "Doe" 
       } 
      ] 
     }, 
     { // Type3 
      "DoB": "1990-01-01" 
     } 
    ] 
} 

mit den folgenden Klassen:

Was ich so etwas wie dies später bekommen möchte

class Type1 { 
    ICollection<object> Children { get; set; } 
} 

class Type2 { 
    public string Name { get; set; } 
    public string Surname { get; set; } 
} 

class Type3 { 
    public DateTime DoB { get; set; } 
} 

class Root 
{ 
    public string Author { get; set; } 
    public string Version { get; set; } 
    public Type1 Children { get; set; } 
} 

Frage

Wie kann ich das deserialisieren in dem Nachspiel C# -Klassen, unter Berücksichtigung der Datentypen und entfernen sie aus dem Baum?

Ich habe versucht, mit einer benutzerdefinierten JsonConverter, aber ich kämpfe mit, wie man den Konverter dynamisch wählen, da der einfachste Weg wäre, ein Attribut auf die Eigenschaft zu setzen, aber es wird nicht unterstützt.

Ein kleines Beispiel wäre großartig.

Antwort

8

Obwohl dieses JSON-Format etwas ungewöhnlich ist und widersteht die Verwendung von Attributen aufgrund der dynamischen Eigenschaftsnamen, ist es immer noch möglich um eine JsonConverter zu deserialisieren es in Ihre bevorzugte Klassenstruktur mit einer kleinen Änderung: Ich würde Ihnen empfehlen, die Children Eigenschaft in der Root Klasse zu einem ICollection<object> zu spiegeln Children Eigenschaft in der Type1 Klasse. Wie es jetzt aussieht, stimmt es nicht mit der Struktur Ihrer gewünschten Ausgabe überein (wobei Children als Array, nicht als Objekt angezeigt wird) und würde andernfalls zusätzlichen Code im Konverter benötigen, um korrekt zu funktionieren.

class Root 
{ 
    public string Author { get; set; } 
    public string Version { get; set; } 
    public ICollection<object> Children { get; set; } 
} 

Hier ist, was ich mit für den Konverter kam (die obige Änderung wird vorausgesetzt):

class CustomConverter : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return (objectType == typeof(Root)); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     JObject obj = JObject.Load(reader); 
     Root root = new Root(); 
     root.Author = (string)obj["Author"]; 
     root.Version = (string)obj["Version"]; 
     root.Children = ((Type1)DeserializeTypeX(obj, serializer)).Children; 
     return root; 
    } 

    private object DeserializeTypeX(JObject obj, JsonSerializer serializer) 
    { 
     JProperty prop = obj.Properties().Where(p => p.Name.StartsWith("data.")).First(); 
     JObject child = (JObject)prop.Value; 
     if (prop.Name == "data.Type1") 
     { 
      List<object> children = new List<object>(); 
      foreach (JObject jo in child["Children"].Children<JObject>()) 
      { 
       children.Add(DeserializeTypeX(jo, serializer)); 
      } 
      return new Type1 { Children = children }; 
     } 
     else if (prop.Name == "data.Type2") 
     { 
      return child.ToObject<Type2>(serializer); 
     } 
     else if (prop.Name == "data.Type3") 
     { 
      return child.ToObject<Type3>(serializer); 
     } 
     throw new JsonSerializationException("Unrecognized type: " + prop.Name); 
    } 

    public override bool CanWrite 
    { 
     get { return false; } 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

Bewaffnet mit diesem Konverter Sie Ihre Klassen wie diese deserialisieren können:

Root root = JsonConvert.DeserializeObject<Root>(json, new CustomConverter()); 

Sie können dann auf das neue Format wie folgt serialisiert:

JsonSerializerSettings settings = new JsonSerializerSettings 
{ 
    DateFormatString = "yyyy-MM-dd", 
    Formatting = Formatting.Indented 
}; 

Console.WriteLine(JsonConvert.SerializeObject(root, settings)); 

Fiddle: https://dotnetfiddle.net/ESNMLE

0

Nicht sicher, ob das funktioniert, aber haben Sie versucht, mit Newtonsoft.Json das Objekt zu serialisieren und JsonProperty-Tags in die Klasseneigenschaften aufzunehmen? Ich weiß, dass dies funktioniert, wenn JSer in eine Klasse deserialisiert wird.

<JsonProperty("user_id")> 
Public Property UserID As String 
//Converts Json {user_id: 123} to class.UserID = 123 

mit Newtonsoft serialisiert wird, umfassen erster Newtonsoft in das Projekt dann

Dim stringJson As String = Newtonsoft.Json.JsonConvert.SerializeObject(root) 
+0

Danke für Ihre Antwort.Ich habe versucht, aber das Problem ist, dass ganze Ebenen entfernt und ersetzt werden müssen, da sie nur als Daten dienen, um zu unterscheiden, welchen Typ sie darstellen, wobei JsonProperty nur zwischen Klassennamen und Json-Eigenschaftsnamen zu mappen ist. –

Verwandte Themen