Newtonsoft Json Serializzatore/Deserializer – utilizzo di oggetti generici invece di JObject?

Ho JSON specificato da un servizio restful sto consumando simile a questo come esempio:

{
  "id": "97",
  "name": "Tom Production",
  "description": null,
  "parameters": [
    {
      "first_parameter_name": "First Parameter Value"
    },
    {
      "second_parameter_name": "Second Parameter Value"
    }
  ]
}

Di notare che i nomi delle proprietà id, nome, descrizione e parametri sono stabiliti come parte della specifica. La raccolta di parametri generici, mostrato nel mio esempio come “first_parameter_name” e “second_parameter_name” non è specificato…. potrebbe essere qualsiasi cosa, e voglio la mappatura genericamente oggetti tipizzati.

Ho dichiarato un oggetto come:

[DataContract (Name = "MyClass")]
public class MyClass
{
    [DataMember (Name = "id")]
    public string Id { get; set; }

    [DataMember(Name = "name")]
    public string Name { get; set; }

    [DataMember(Name = "description")]
    public string Description { get; set; }

    [DataMember(Name = "parameters")]
    public List<object> Parameters { get; set; }
}

Serializzazione funziona bene, esattamente come mi aspetto:

        var myObject = new MyClass();
        myObject.Id = "97";
        myObject.Name = "Tom Production";
        myObject.Parameters = new List<object>();
        myObject.Parameters.Add(new { first_parameter_name = "First Parameter Value" });
        myObject.Parameters.Add(new { second_parameter_name = "Second Parameter Value" });
        string json = JsonConvert.SerializeObject(myObject);
        Console.WriteLine(json);

rendimenti JSON sto cercando, esattamente come all’inizio di questo distacco.

TUTTAVIA.

Deserializzazione NON funziona bene. Se ha funzionato il modo in cui spero, che sarebbe quello di creare tipi generici, proprio come mi aveva creato, e il seguente codice dovrebbe funzionare…. ma invece si lancia una riflessione eccezione:

        var myNewObject = JsonConvert.DeserializeObject<MyClass>(json);

        foreach (object o in myNewObject.Parameters)
        {
            Type t = o.GetType();
            Console.WriteLine("\tType is {0}", t);
            foreach (PropertyInfo pi in t.GetProperties(BindingFlags.Instance | BindingFlags.Public))
            {
                Console.WriteLine("\t\tName is {0}", pi.Name);
                Console.WriteLine("\t\tValue is {0}", pi.GetValue(o, null));
            }
        }

Invece, devo scrivere il codice che è Newtonsoft specifici (ick) per utilizzare un tipo di falso Newtonsoft riflessione:

        var myNewObject = JsonConvert.DeserializeObject<MyClass>(json);

        foreach (object o in myNewObject.Parameters)
        {
            var jo = o as JObject;
            if (jo != null)
            {
                foreach (JProperty prop in jo.Properties())
                {
                    Console.WriteLine("\t\tName is {0}", prop.Name);
                    Console.WriteLine("\t\tValue is {0}", prop.Value);
                }
            }
        }

C’è un modo che posso controllare il Deserializer in modo che genererà il corretto tipi generici piuttosto che il JObject tipo con la JProperties?

Molte grazie in anticipo.

Anonimo tipi di compilare classi a tempo. È possibile creare nel codice perché il compilatore imposta classi concrete per voi dietro le quinte. Quando la deserializzazione, non è possibile ri-creare l’anonimo classi perché i tipi sono dipendente dal JSON, che è noto solo a tempo di esecuzione. Che è il motivo per cui Json.Net non è possibile ricreare i tipi anonimi. La soluzione è usare un List<Dictionary<string, string>> come @Tim S. suggerito.
Se hai trovato una soluzione al tuo problema, allora il post come una risposta alla domanda, non come modificare la domanda stessa. Se la risposta è sufficiente, quindi non c’è bisogno di fare anche questo; basta lasciarlo come si trova.

OriginaleL’autore Stephan G | 2015-01-09

1 risposta

  1. 10

    JObject mappa più direttamente Dizionario<string, object>, dal momento che sono semplicemente una raccolta di chiavi e valori. Se si sa che il valore è sempre una string, si può fare un Dictionary<string, string>.

    [DataMember(Name = "parameters")]
    public List<Dictionary<string, object>> Parameters { get; set; }
    
    //or
    
    [DataMember(Name = "parameters")]
    public List<Dictionary<string, string>> Parameters { get; set; }
    
    //e.g.
    var myNewObject = JsonConvert.DeserializeObject<MyClass>(json);
    
    foreach (var dict in myNewObject.Parameters)
    {
        foreach (var pair in dict)
        {
            Console.WriteLine("\t\tKey is {0}", pair.Key);
            Console.WriteLine("\t\tValue is {0}", pair.Value);
        }
    }
    Forse questa è una soluzione praticabile…. curioso di vedere se qualcuno ha idee su come ottenere il vostro modo “voglio davvero”, ma questo potrebbe funzionare. Unico problema è che i Dizionari, naturalmente, non consentono di duplicati di chiavi, che la specifica potrebbe consentire, in teoria. Anche se ora che sto guardando il tuo codice con più attenzione, vedo che è un elenco di dizionari, in modo che potesse andare bene. Sarebbe bello se NameValueCollection…. ma ho il sospetto che non…. Si può tentare.
    JSON non ammette duplicati di chiavi, o, quindi, se non includono i duplicati all’interno di un oggetto, che stanno dando l’input non valido. Sono sicuro che non funziona out-of-the-box, ma mi aspetto che con un convertitore personalizzato è possibile sostituire il List<Dictionary<..>> con un unico NameValueCollection, se questo suona come una scelta migliore per la vostra specifica di dati.
    Grazie per l’aiuto.

    OriginaleL’autore Tim S.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *