Bei C# handelt es sich um eine stark typisierte Programmiersprache, dass bedeutet, dass ein Variablentyp bekannt sein muss und sich dieser auch zur Laufzeit nicht ändern kann. Nun kann es jedoch vorkommen, dass die JSON-Struktur manchmal eine Liste von Objekten und manchmal nur ein einzelnen Objekt beinhaltet. Wenn man nun versucht dieses zu deserialisieren, stößt man auf ein Problem. Denn der Datentyp ist nicht mehr eindeutig und daher kann er nicht konvertiert werden. Ich möchte hier nun zeigen, wie man einen eigenen Json-Converter mit Newtonsoft.JSON schreiben kann, welcher dieses beschriebene Problem umgeht.
Zunächst möchte ich ein einfache Beispiel für eine Json-Struktur liefern, welche das Problem verdeutlicht.
[
{
"title": "My Title",
"genre": "Action"
},
{
"title": "My Other Title",
"genre": [
"Action",
"Thriller"
]
}
]
Der Objekt Genre ist entweder ein String oder eine Liste von Strings. Damit die Deserialisierung nun mit Newtonsoft.JSON funktioniert, schreiben wir einen Converter. Dieses wollen wir SingleValueArrayConverter nennen und hat die folgende Struktur.
public class SingleValueArrayConverter<T> : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return true;
}
public override object ReadJson(JsonReader reader, Type objectType,
object existingValue, JsonSerializer serializer)
{
var retVal = new object();
switch (reader.TokenType)
{
case JsonToken.StartObject:
var instance = (T)serializer.Deserialize(reader, typeof(T));
retVal = new List<T> { instance };
break;
case JsonToken.StartArray:
var lst = serializer.Deserialize(reader, objectType);
retVal = lst;
break;
}
return retVal;
}
public override void WriteJson(JsonWriter writer, object value,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
Um diesen Converter nur verwenden zu können, muss dieser bei der Definition der Datenstruktur mit angegeben werden. Für unser kleines JSON-Beispiel ergibt sich nun der folgende Aufbau.
public class MyObject
{
[JsonConverter(typeof(SingleValueArrayConverter<string>))]
[JsonProperty("genre")]
public List<string> Genre { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
}
Wie man diesem Beispiel entnehmen kann, geben wir nun immer eine Liste von Einträgen zurück, wobei diese Liste auch nur ein Element enthalten kann, wenn in der JSON-Struktur nur ein einzelner String bzw. Objekt angegeben ist.