2013-05-04 6 views
7

Ich bemerke, es gibt einige andere Ergebnisse auf Stackoverflow für diese Frage, aber sie scheinen nicht zu funktionieren oder sind vage. Unter Verwendung des populärsten Ergebnisses habe ich folgendes zusammengestellt:Wie kann ich mit JSON.NET einen Wert behandeln, der manchmal ein Objekt und manchmal ein Array des Objekts ist?

Das Problem ist, dass, wenn JSON zurückkommt und in einen meiner benutzerdefinierten Typen serialisiert wird, eines der Bits von JSON manchmal ein Array ist und manchmal nur ein Zeichenfolge. Wenn mein benutzerdefinierter Typ eine Zeichenfolge hat und der JSON ein Array ist, erhalte ich einen Fehler. Dasselbe passiert umgekehrt, wenn JSON ein Objekt ist und mein benutzerdefinierter Typ ein Array ist. Es kann nur nicht auf die Eigenschaft abgebildet werden.

Ich beschloss, dies zu lösen, ich möchte die Deserialisierung dieser bestimmten Eigenschaft überschreiben, und wenn es ein Objekt ist, möchte ich es in ein Array von 1 Objekt konvertieren.

In dem Objekt, zu dem ich serialisieren möchte, habe ich einen JsonConverter hinzugefügt, von dem ich denke, dass er die Deserialisierung überschreiben wird.

[JsonConverter(typeof(ArrayOrSingleObjectConverter<string>))] 
public List<string> person { get; set; } 

Die Idee ist, dass der benutzerdefinierte Konverter ein einzelnes Objekt in ein Array konvertieren wird. Wenn der JSON also "Hello" ist, wird die Person als eine Liste mit "Hello" definiert, anstatt eine Ausnahme auszugeben, die besagt, dass String nicht in List konvertiert werden kann.

Wenn es bereits ein Array ist, sollte es einfach in Ruhe lassen.

Der Konverter sieht wie folgt aus:

public class ArrayOrSingleObjectConverter<T> : JsonConverter 
{ 
    public override bool CanConvert(Type objectType) 
    { 
     return true; // Not sure about this but technically it can accept an array or an object, so everything is game. 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (objectType == typeof(List<T>)) 
     { 
      return serializer.Deserialize<List<T>>(reader); 
     } 
     else 
     { 
      var singleObject = serializer.Deserialize<T>(reader); 
      var objectAsList = new List<T>(); 
      objectAsList.Add(singleObject); 
      return objectAsList; 
     } 
    } 

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

Es funktioniert nicht. Der obige Code löst eine Ausnahme aus, wenn versucht wird, eine einzelne Zeichenfolge zu deserialisieren, die besagt, dass sie nicht in eine List innerhalb der if-Anweisung umgewandelt werden kann (der 'Objekttyp' ist jedoch eine Liste).

Ich bin schwer zu verstehen, was genau die Lese-und Schreibmethoden tun. In der anderen Antwort auf stackoverflow schlägt es vor, eine NotImplementedException in die Lese-Methode zu werfen. Aber wenn ich das tue, wird die Lesemethode aufgerufen und die Ausnahme wird ausgelöst.

Ich denke, ich bin auf dem richtigen Weg, aber ich brauche einen Anstupser in die richtige Richtung. Ich denke, ich bin etwas verwirrt darüber, was die ReadJSon-Methode macht und was ihre Parameter bedeuten.

Ich verstehe nicht wirklich, wo der Wert herkommt, dass es deserializing ist, da ich es nicht in der Deserialize-Methode angegeben habe.

Ich bin ein bisschen über meine Tiefe auf diesem.

+0

Können Sie dieses "variable" Objekt nicht zu einem 'System.Object' deserialisieren? Sie könnten dann den Laufzeittyp überprüfen und Ihr Ding machen. –

Antwort

9

Ich hatte etwas ähnliches letzte Woche zu tun und ich kam mit dem Follow-up, die für eine Liste eher als ein Array

internal class GenericListCreationJsonConverter<T> : JsonConverter 
{ 

    public override bool CanConvert(Type objectType) 
    { 
     return true; 
    } 

    public override bool CanRead 
    { 
     get { return true; } 
    } 

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.StartArray) 
     { 
      return serializer.Deserialize<List<T>>(reader); 
     } 
     else 
     { 
      T t = serializer.Deserialize<T>(reader); 
      return new List<T>(new[] { t }); 
     } 
    } 

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

Excellent thanks, Ich fand am Ende etwas Ähnliches herauszufinden, aber ich mag Ihre Methode, wie ich mit Generika kämpfte :) – NibblyPig

1

Ich mag diese Methode, die Json.NET haben die schwere alles macht gut funktioniert Heben. Als Ergebnis unterstützt es alles, was Json.NET unterstützt (Liste <>, ArrayList, stark typisierte Arrays, usw.).

public class FlexibleCollectionConverter : JsonConverter 
{ 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     serializer.Serialize(writer, value); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     if (reader.TokenType == JsonToken.StartArray) 
     { 
      return serializer.Deserialize(reader, objectType); 
     } 

     var array = new JArray(JToken.ReadFrom(reader)); 
     return array.ToObject(objectType); 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return typeof (IEnumerable).IsAssignableFrom(objectType); 
    } 
} 
+0

Funktioniert nicht für JSON-Array –