2017-09-05 3 views
0

Ich muss Remote-Konnektivität für eine vorhandene Berichtschnittstelle implementieren, die Serialisierung und Deserialisierung der Datenklassen erfordert. Hier ist eine vereinfachte Version der Klassen und Schnittstellen:JSON Newtonsoft C# Deserialize Liste von Objekten verschiedener Typen

public interface IBase 
    { 
     string Name { get; } 
    } 

    public interface IDerived1 
    { 
     int Value { get; } 
    } 

    public interface IDerived2 
    { 
     bool Value { get; } 
    } 

    public class Base : IBase 
    { 
     public string Name { get; protected set; } 
    } 

    public class Derived1 : Base, IDerived1 
    { 
     public int Value { get; protected set; } 
    } 

    public class Derived2 : Base, IDerived2 
    { 
     public bool Value { get; protected set; } 
    } 

Als Eingabeparameter bekomme ich

IEnumerable<IBase> reportingData 

Also diese Sammlung eine beliebige Anzahl und Kombination von Instanzen von ‚Derived1‘ enthalten und ‚Derived2‘ . Ich serialise dann die Sammlung wie folgt aus:

string serialisedReportingData = JsonConvert.SerializeObject(reportingData); 

Was mich dieses zum Beispiel gibt:

[{ "Wert": 11 "Name": "Product Number"}, { "Wert": false , "Name": "Ausgang 1 aktiviert"}]

Offensichtlich mit diesen Daten ist De-Serialisierung unmöglich, da der Typ der einzelnen Auflistungseinträge nicht in dem JSON ist. Ich könnte zum Beispiel den Typ Teil des JSON machen oder eine zusätzliche Sammlung von Typen zur Verwendung während der Deserialisierung bereitstellen.

Ich habe CustomCreationConverter Überlastungen verwendet, bevor sie mit

JsonConvert.DeserializeObject<IEnumerable<Ixxx>>(...); 

Art von Szenarien zu bewältigen, aber dies nur zu einem einzigen Interface-Typ innerhalb des IEnumerable angewendet. In meinem obigen Beispiel habe ich zwei: IDerived1 und IDerived2.

Meine Fragen/Themen:

a) Ich bin nicht sicher, wie ein CustomCreationConverter die sich mit mehr als einem Interface-Typ geschrieben werden konnte, und ich weiß nicht, wie die Art, in diese zu bekommen.

b) Ich würde Ihre Vorschläge zur Implementierung einer Lösung, die mir die gleiche Deserialisierungsausgabe geben würde wie die IEnumerable ReportingData, die ich als Eingabe erhalten habe, sehr schätzen.

Ich würde gerne ein funktionierendes Codebeispiel, wo möglich, schätzen.

Vielen Dank im Voraus, Christian

+0

Wenn Sie nicht wollen, sind '„$ type“' Informationen finden Sie unter [Wie benutzerdefinierte JsonConverter in JSON.NET implementieren eine Liste der Basisklasse Objekte deserialisieren?] (Https: // Stackoverflow.com/q/8030538) und [Deserialisierung polymorpher JSON-Klassen ohne Typinformationen unter Verwendung von json.net] (https://stackoverflow.com/q/19307752). – dbc

Antwort

1

Update: (von dem Kommentar von DBC inspiriert)

Sie sollen ein SerializationBinder verwenden, wenn sie mit Typnamen deserialisieren. Siehe hier für die KnownTypesBinder. (Newtonsoft.Json Version größer 10 wird benötigt)

Zuerst, wenn Sie Ihre Eigenschaften einstellen möchten, müssen Sie sie public machen. Dann können Sie eine JsonSerializerSettings Serialisieren/Deserialisieren verwenden.

List<IBase> loList = new List<IBase>(); 
loList.Add(new Base() { Name = "Base" }); 
loList.Add(new Derived1() { Name = "Derived1", Value = 3 }); 
loList.Add(new Derived2() { Name = "Derived2", Value = true }); 

KnownTypesBinder loKnownTypesBinder = new KnownTypesBinder() 
{ 
    KnownTypes = new List<Type> { typeof(Base), typeof(Derived1), typeof(Derived2) } 
}; 

IEnumerable<IBase> reportingData = loList.AsEnumerable(); 
JsonSerializerSettings loJsonSerializerSettings = new JsonSerializerSettings() 
{ 
    TypeNameHandling = TypeNameHandling.Objects, 
    SerializationBinder = loKnownTypesBinder 
}; 

string lsOut = JsonConvert.SerializeObject(reportingData, loJsonSerializerSettings); 
reportingData = JsonConvert.DeserializeObject<IEnumerable<IBase>>(lsOut, loJsonSerializerSettings); 

Wenn Sie die JsonSerializerSettings so verwenden, werden die Typinformationen in dem JSON-String enthalten sein.

[{ 
     "$type": "Base", 
     "Name": "Base" 
    }, { 
     "$type": "Derived1", 
     "Value": 3, 
     "Name": "Derived1" 
    }, { 
     "$type": "Derived2", 
     "Value": true, 
     "Name": "Derived2" 
    } 
] 
+0

'$ type' Informationen sollten aus Sicherheitsgründen bereinigt werden. Weitere Informationen finden Sie unter [Vorsicht vor Typbezeichnungen in Newtonsoft Json] (https://stackoverflow.com/q/39565954). – dbc

+0

@ dbc: Thx. Ich habe meine Antwort aktualisiert. – PinBack

+0

Vielen Dank SOOOO viel! Ich habe nicht erwartet, dass die Antwort so direkt ist. Nicht nur ich, sondern auch einige meiner Kollegen werden Ihre Weisheit sehr schätzen! :-) – Christian

Verwandte Themen