Ich habe eine Klassendefinition, die eine Eigenschaft enthält, die eine Schnittstelle zurückgibt.
public class Foo
{
public int Number { get; set; }
public ISomething Thing { get; set; }
}
Beim Versuch, die Foo-Klasse mit Json.NET zu serialisieren, wird die folgende Fehlermeldung angezeigt: "Es konnte keine Instanz vom Typ 'ISomething' erstellt werden. ISomething kann eine Schnittstelle oder eine abstrakte Klasse sein."
Gibt es ein Json.NET-Attribut oder einen Konverter, mit dem ich eine konkrete Something
Klasse angeben kann , die während der Deserialisierung verwendet werden soll?
.net
serialization
json.net
dthrasher
quelle
quelle
Antworten:
Mit Json.NET können Sie unter anderem Folgendes tun :
Das
TypeNameHandling
Flag fügt$type
dem JSON eine Eigenschaft hinzu, mit der Json.NET erkennt, in welchen konkreten Typ das Objekt deserialisiert werden soll. Auf diese Weise können Sie ein Objekt deserialisieren, während Sie eine Schnittstelle oder eine abstrakte Basisklasse erfüllen.Der Nachteil ist jedoch, dass dies sehr Json.NET-spezifisch ist. Das
$type
wird ein vollständig qualifizierter Typ sein, also , wenn Sie es mit Typ - Informationen sind die Serialisierung ,, die Deserializer muss in der Lage sein , es so gut zu verstehen.Dokumentation: Serialisierungseinstellungen mit Json.NET
quelle
TypeNameHandling
. Weitere Informationen finden Sie unter TypeNameHandling-Warnung in Newtonsoft Json .Sie können dies durch die Verwendung der JsonConverter-Klasse erreichen. Angenommen, Sie haben eine Klasse mit einer Schnittstelleneigenschaft.
Ihr JsonConverter ist für die Serialisierung und De-Serialisierung der zugrunde liegenden Eigenschaft verantwortlich.
Wenn Sie mit einer über Json.Net deserialisierten Organisation arbeiten, ist die zugrunde liegende IPerson für die Owner-Eigenschaft vom Typ Tycoon.
quelle
Anstatt ein benutzerdefiniertes JsonSerializerSettings-Objekt mit der Option TypeNameHandling.Objects an JsonConvert.SerializeObject () zu übergeben, können Sie diese bestimmte Schnittstelleneigenschaft einfach mit einem Attribut markieren, damit der generierte JSON nicht mit den Eigenschaften "$ type" aufgebläht wird auf JEDEM Objekt:
quelle
In der neuesten Version des Newtonsoft Json-Konverters eines Drittanbieters können Sie einen Konstruktor mit einem konkreten Typ festlegen, der sich auf die Schnittstelle bezieht.
Solange etwas etwas implementiert, sollte dies funktionieren. Setzen Sie auch keinen leeren Standardkonstruktor, falls der JSon-Konverter versucht, diesen zu verwenden. Sie müssen ihn zwingen, den Konstruktor zu verwenden, der den konkreten Typ enthält.
PS. Auf diese Weise können Sie Ihre Setter auch privat machen.
quelle
Hatte das gleiche Problem, also kam ich auf meinen eigenen Konverter, der bekannte Typenargumente verwendet.
Ich habe zwei Erweiterungsmethoden zum Deserialisieren und Serialisieren definiert:
Sie können Ihre eigene Art des Vergleichens und Identifizierens von Typen in den Konvertierungen definieren. Ich verwende nur den Klassennamen.
quelle
Normalerweise habe ich die Lösung immer mit verwendet,
TypeNameHandling
wie von DanielT vorgeschlagen, aber in Fällen, in denen ich hier keine Kontrolle über den eingehenden JSON hatte (und daher nicht sicherstellen kann, dass er eine$type
Eigenschaft enthält), habe ich einen benutzerdefinierten Konverter geschrieben, mit dem Sie nur explizit angeben können der konkrete Typ:Hierbei wird nur die Standard-Serializer-Implementierung von Json.Net verwendet, während der konkrete Typ explizit angegeben wird.
Der Quellcode und eine Übersicht finden Sie in diesem Blogbeitrag .
quelle
Ich wollte nur das Beispiel vervollständigen, das uns @Daniel T. oben gezeigt hat:
Wenn Sie diesen Code zum Serialisieren Ihres Objekts verwenden:
Der Code zum Deserialisieren des JSON sollte folgendermaßen aussehen:
So wird ein JSON angepasst, wenn das
TypeNameHandling
Flag verwendet wird:quelle
Ich habe mich das Gleiche gefragt, aber ich fürchte, es geht nicht.
Schauen wir es uns so an. Sie übergeben JSon.net eine Datenfolge und einen Typ, in den Sie deserialisieren möchten. Was kann JSON.net tun, wenn es auf etwas trifft? Es kann keine neue Art von ISomething erstellen, da ISomething kein Objekt ist. Es kann auch kein Objekt erstellen, das ISomething implementiert, da es keine Ahnung hat, welches der vielen Objekte, die möglicherweise ISomething erben, verwendet werden soll. Schnittstellen können automatisch serialisiert, aber nicht automatisch deserialisiert werden.
Was ich tun würde, wäre zu versuchen, ISomething durch eine Basisklasse zu ersetzen. Auf diese Weise können Sie möglicherweise den gewünschten Effekt erzielen.
quelle
Hier ist ein Verweis auf einen Artikel von ScottGu
Auf dieser Grundlage habe ich einen Code geschrieben, der meiner Meinung nach hilfreich sein könnte
Und so würden Sie es nennen
Wenn ich es richtig verstehe, müssen Sie meiner Meinung nach keine konkrete Klasse angeben, die die Schnittstelle für die JSON-Serialisierung implementiert.
quelle