Ich versuche, das hier angegebene JSON.net-Beispiel zu erweitern: http://james.newtonking.com/projects/json/help/CustomCreationConverter.html
Ich habe eine andere Unterklasse, die von der Basisklasse / Schnittstelle abgeleitet ist
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Employee : Person
{
public string Department { get; set; }
public string JobTitle { get; set; }
}
public class Artist : Person
{
public string Skill { get; set; }
}
List<Person> people = new List<Person>
{
new Employee(),
new Employee(),
new Artist(),
};
Wie deserialisiere ich, wenn ich Json zurück zu List <Person> folge?
[
{
"Department": "Department1",
"JobTitle": "JobTitle1",
"FirstName": "FirstName1",
"LastName": "LastName1"
},
{
"Department": "Department2",
"JobTitle": "JobTitle2",
"FirstName": "FirstName2",
"LastName": "LastName2"
},
{
"Skill": "Painter",
"FirstName": "FirstName3",
"LastName": "LastName3"
}
]
Ich möchte TypeNameHandling JsonSerializerSettings nicht verwenden. Ich suche speziell nach einer benutzerdefinierten JsonConverter-Implementierung, um dies zu handhaben. Die Dokumentation und Beispiele dazu sind im Netz ziemlich spärlich. Ich kann die überschriebene Implementierung der ReadJson () -Methode in JsonConverter anscheinend nicht richtig ausführen.
c#
json
json.net
deserialization
Snakebyte
quelle
quelle
Antworten:
Unter Verwendung des Standards
CustomCreationConverter
hatte ich Probleme damit, den richtigen Typ (Person
oderEmployee
) zu generieren , da Sie den JSON analysieren müssen, um dies festzustellen, und es gibt keine eingebaute Möglichkeit, dies mit derCreate
Methode zu tun .Ich habe einen Diskussionsthread zur Typkonvertierung gefunden, der die Antwort lieferte. Hier ist ein Link: Typkonvertierung .
Was erforderlich ist, ist eine Unterklasse
JsonConverter
, das Überschreiben derReadJson
Methode und das Erstellen einer neuen abstraktenCreate
Methode, die a akzeptiertJObject
.Die überschriebene
ReadJson
Methode erstellt eineJObject
und ruft dieCreate
Methode (implementiert von unserer abgeleiteten Konverterklasse) auf, wobei dieJObject
Instanz übergeben wird.Diese
JObject
Instanz kann dann analysiert werden, um den richtigen Typ zu bestimmen, indem das Vorhandensein bestimmter Felder überprüft wird.Beispiel
quelle
JsonReader
in der erstelltenReadJson
Methode nicht erben keine der Konfigurationswerte des ursprünglichen Leser (Culture
,DateParseHandling
,DateTimeZoneHandling
,FloatParseHandling
, etc ...). Diese Werte sollten werden kopiert , bevor die neue VerwendungJsonReader
inserializer.Populate()
.JsonConverter
eine Eigenschaft namensCanRead
und hatCanWrite
. Wenn Sie keine benutzerdefinierteWriteJson
Implementierung benötigen , reicht es aus, dieCanWrite
Rückkehr zuzulassenFALSE
. Das System greift dann auf das Standardverhalten zurück. @jdavies: Bitte füge das deiner Antwort hinzu. Andernfalls stürzt es bei der Serialisierung ab.Die obige Lösung für das
JsonCreationConverter<T>
ist überall im Internet, hat aber einen Fehler, der sich in seltenen Fällen manifestiert. Der neue JsonReader, der mit der ReadJson-Methode erstellt wurde, erbt keinen der Konfigurationswerte des ursprünglichen Lesegeräts (Culture, DateParseHandling, DateTimeZoneHandling, FloatParseHandling usw.). Diese Werte sollten kopiert werden, bevor der neue JsonReader in serializer.Populate () verwendet wird.Dies ist das Beste, was ich finden konnte, um einige der Probleme mit der obigen Implementierung zu beheben, aber ich denke immer noch, dass einige Dinge übersehen werden:
Update Ich habe dies aktualisiert, um eine explizitere Methode zu haben, mit der eine Kopie eines vorhandenen Readers erstellt wird. Dies kapselt nur den Vorgang des Kopierens über einzelne JsonReader-Einstellungen. Im Idealfall wird diese Funktion in der Newtonsoft-Bibliothek selbst beibehalten. Derzeit können Sie jedoch Folgendes verwenden:
Dies sollte wie folgt verwendet werden:
Ältere Lösung folgt:
quelle
Ich dachte nur, ich würde eine Lösung teilen, die auch auf dieser basiert und mit dem Knowntype-Attribut unter Verwendung von Reflection funktioniert. Ich musste eine abgeleitete Klasse von einer beliebigen Basisklasse abrufen. Die Lösung kann von einer Rekursion profitieren, um die am besten passende Klasse zu finden, obwohl ich sie in meiner nicht benötigte In diesem Fall erfolgt der Abgleich nach dem Typ, der dem Konverter zugewiesen wurde. Wenn er KnownTypes hat, werden alle gescannt, bis er mit einem Typ übereinstimmt, der alle Eigenschaften in der JSON-Zeichenfolge aufweist. Als erster wird der übereinstimmende Typ ausgewählt.
Die Verwendung ist so einfach wie:
im obigen Fall ist ret vom Typ B.
JSON-Klassen:
Konvertercode:
quelle
Das Projekt JsonSubTypes implementiert einen generischen Konverter, der diese Funktion mithilfe von Attributen verarbeitet.
Für das hier bereitgestellte konkrete Beispiel funktioniert es wie folgt:
quelle
Dies ist eine Erweiterung der Antwort des Totems. Es macht im Grunde das Gleiche, aber die Eigenschaftsübereinstimmung basiert auf dem serialisierten json-Objekt und spiegelt nicht das .net-Objekt wider. Dies ist wichtig, wenn Sie [JsonProperty] verwenden, den CamelCasePropertyNamesContractResolver verwenden oder etwas anderes tun, das dazu führt, dass der json nicht mit dem .net-Objekt übereinstimmt.
Die Verwendung ist einfach:
Konvertercode:
quelle
Als weitere Variante der Totem-Lösung für bekannte Typen können Sie mithilfe von Reflection einen generischen Typ-Resolver erstellen, um zu vermeiden, dass bekannte Typattribute verwendet werden müssen.
Dies verwendet eine ähnliche Technik wie Juval Lowys GenericResolver für WCF.
Solange Ihre Basisklasse abstrakt oder eine Schnittstelle ist, werden die bekannten Typen automatisch ermittelt, anstatt mit bekannten Typattributen dekoriert werden zu müssen.
In meinem Fall habe ich mich dafür entschieden, eine $ type-Eigenschaft zu verwenden, um den Typ in meinem json-Objekt zu bestimmen, anstatt zu versuchen, ihn aus den Eigenschaften zu bestimmen, obwohl Sie hier andere Lösungen ausleihen könnten, um die eigenschaftsbasierte Bestimmung zu verwenden.
Es kann dann als Formatierer installiert werden
quelle
Hier ist eine andere Lösung, die die Verwendung von vermeidet
jObject.CreateReader()
und stattdessen eine neue erstelltJsonTextReader
(dies ist das Verhalten, das von der StandardmethodeJsonCreate.Deserialze
verwendet wird:quelle
In vielen Fällen befindet sich die Implementierung im selben Namespace wie die Schnittstelle. Also habe ich mir Folgendes ausgedacht:
Daher können Sie dies global wie folgt einschließen:
quelle
Mit der Idee von Totem und Zlangner habe ich eine erstellt
KnownTypeConverter
, die in der Lage ist, den am besten geeigneten Erben zu bestimmen, wobei berücksichtigt wird, dass JSON-Daten möglicherweise keine optionalen Elemente enthalten.Der Dienst sendet also eine JSON-Antwort, die eine Reihe von Dokumenten enthält (eingehend und ausgehend). Dokumente haben sowohl gemeinsame als auch unterschiedliche Elemente. In diesem Fall sind die Elemente, die sich auf die ausgehenden Dokumente beziehen, optional und können fehlen.
In diesem Zusammenhang wurde eine Basisklasse
Document
erstellt, die einen gemeinsamen Satz von Eigenschaften enthält. Es werden auch zwei Vererbungsklassen erstellt: -OutgoingDocument
fügt zwei optionale Elemente hinzu"device_id"
und"msg_id"
; -IncomingDocument
fügt ein obligatorisches Element hinzu"sender_id"
;Die Aufgabe bestand darin, einen Konverter zu erstellen, der basierend auf JSON-Daten und Informationen von KnownTypeAttribute die am besten geeignete Klasse ermitteln kann, mit der Sie die größte Menge empfangener Informationen speichern können. Es sollte auch berücksichtigt werden, dass JSON-Daten möglicherweise keine optionalen Elemente enthalten. Um die Anzahl der Vergleiche von JSON-Elementen und Eigenschaften von Datenmodellen zu verringern, habe ich beschlossen, die Eigenschaften der Basisklasse nicht zu berücksichtigen und nur die Eigenschaften der Vererbungsklassen mit JSON-Elementen zu korrelieren.
Daten aus dem Dienst:
Datenmodelle:
Konverter:
PS: In meinem Fall, wenn kein Konverter vom Konverter ausgewählt wurde (dies kann passieren, wenn die JSON-Daten nur Informationen aus der Basisklasse enthalten oder die JSON-Daten keine optionalen Elemente aus der enthalten
OutgoingDocument
), dann ein Objekt derOutgoingDocument
Klasse wird erstellt, da es zuerst in der Liste derKnownTypeAttribute
Attribute aufgeführt ist. Auf Ihren Wunsch können Sie die ImplementierungKnownTypeConverter
in dieser Situation variieren .quelle