2017-09-05 3 views
0

Je dois mettre en œuvre la connectivité à distance pour une interface de génération de rapports existante, ce qui nécessite la sérialisation et la désérialisation des classes de données. Voici une version simplifiée des classes et interfaces:JSON Newtonsoft C# Deserialize Liste des objets de différents types

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; } 
    } 

En tant que paramètre d'entrée je reçois

IEnumerable<IBase> reportingData 

donc cette collection peut contenir un nombre quelconque et la combinaison des instances de « Derived1 » et « Derived2 » . Je me suis alors serialise la collection comme ceci:

string serialisedReportingData = JsonConvert.SerializeObject(reportingData); 

Ce qui me donne par exemple ceci:

[{ "Valeur": 11, "Nom": "Numéro de produit"}, { "Valeur": false , "Name": "Output 1 Enabled"}]

Évidemment, avec ces seules données, la désérialisation est impossible, car le type des entrées de collection individuelles n'est pas dans le JSON. Je pourrais par exemple faire le type de JSON ou fournir une collection supplémentaire de types à utiliser lors de la dé-sérialisation.

Je l'ai utilisé avant CustomCreationConverter de surcharge pour traiter

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

type de scénarios, mais cela ne s'applique à un seul type d'interface à l'intérieur du IEnumerable. Dans mon exemple ci-dessus, j'ai deux: IDerived1 et IDerived2.

Mes questions/problèmes:

a) Je ne suis pas sûr de savoir comment un CustomCreationConverter pourrait être écrit qui traite plus d'un type d'interface et je ne sais pas comment obtenir le type dans ce.

b) J'adorerais vos suggestions sur la façon d'implémenter une solution qui me donnerait le même résultat de désérialisation que le 'IEnumerable reportingData' que j'ai reçu en entrée.

J'apprécierais beaucoup un exemple de code de travail, si possible.

Un grand merci à l'avance, Christian

+0

Si vous ne souhaitez pas inclure l'information ' "$ type"', voir [Comment mettre en œuvre la coutume JsonConverter dans JSON.NET désérialiser une liste d'objets de classe de base?] (Https: // stackoverflow.com/q/8030538) et [Désérialisation des classes json polymorphes sans informations de type en utilisant json.net] (https://stackoverflow.com/q/19307752). – dbc

Répondre

1

Mise à jour: (inspiré par le commentaire de DBC)

Vous devez utiliser un SerializationBinder quand désérialisation avec des noms de type. Voir ici pour le KnownTypesBinder. (Newtonsoft.Json Version plus 10 est nécessaire)

Tout d'abord, si vous souhaitez définir vos propriétés, vous devez les faire public. Ensuite, vous pouvez utiliser un JsonSerializerSettings pour sérialiser/désérialiser.

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); 

Si vous utilisez le JsonSerializerSettings comme ça, les informations de type sera inclure dans la chaîne JSON.

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

Les informations '$ type' devraient être nettoyées pour des raisons de sécurité. Voir [TypeNameHandling Caution dans Newtonsoft Json] (https://stackoverflow.com/q/39565954) pour plus de détails. – dbc

+0

@dbc: Thx. J'ai mis à jour ma réponse. – PinBack

+0

Merci beaucoup SOOOO! Je ne m'attendais pas à ce que la réponse soit aussi simple. Non seulement moi mais aussi quelques uns de mes collègues apprécieront votre sagesse! :-) – Christian