Deserializza l'oggetto json in oggetto dinamico utilizzando Json.net


426

È possibile restituire un oggetto dinamico da una deserializzazione json usando json.net? Vorrei fare qualcosa del genere:

dynamic jsonResponse = JsonConvert.Deserialize(json);
Console.WriteLine(jsonResponse.message);

1
Considera di generare la classe C # da JSON json2csharp.com e utilizzare la classe generata anziché dinamica
— Michael Freidgeim


Come suggerisci a StackOverflow di chiudere una domanda come "troppo vecchia"? Sono passati sei anni, ci sono risposte valide e suggerimenti ragionevoli per ogni versione di .net da allora ... così tanti che non sono più davvero utili.
— Andrew Lorien,

Risposte:


546

Json.NET ci permette di fare questo:

dynamic d = JObject.Parse("{number:1000, str:'string', array: [1,2,3,4,5,6]}");

Console.WriteLine(d.number);
Console.WriteLine(d.str);
Console.WriteLine(d.array.Count);

Produzione:

 1000
 string
 6

Documentazione qui: LINQ to JSON con Json.NET

Vedi anche JObject.Parse e JArray.Parse


36
Si noti che per gli array la sintassi è JArray.Parse.
— Jgillich,

4
Perché dobbiamo usare la parola dinamica? ho paura mai usato prima: D
— MonsterMMORPG,

3
In VB.Net devi fareDim d As Object = JObject.Parse("{number:1000, str:'string', array: [1,2,3,4,5,6]}")
— ilans

2
@MonsterMMORPG Dovresti essere :) La dinamica è un modello anti in quasi tutte le circostanze, ma, di tanto in tanto, potresti avere una situazione in cui è ragionevole usarlo.
— Pluc

4
Con Newtonsoft.Json 8.0.3 (.NET 4.5.2): Microsoft.CSharp.RuntimeBinder.RuntimeBinderException si è verificato HResult = -2146233088 Messaggio = 'Newtonsoft.Json.Linq.JObject' non contiene una definizione per 'numero' Origine = Microsoft .CSharp StackTrace: at Microsoft.CSharp.RuntimeBinder.RuntimeBinderController.SubmitError (CError pError)
— user4698855

107

A partire da Json.NET 4.0 Release 1, esiste il supporto dinamico nativo:

[Test]
public void DynamicDeserialization()
{
    dynamic jsonResponse = JsonConvert.DeserializeObject("{\"message\":\"Hi\"}");
    jsonResponse.Works = true;
    Console.WriteLine(jsonResponse.message); // Hi
    Console.WriteLine(jsonResponse.Works); // True
    Console.WriteLine(JsonConvert.SerializeObject(jsonResponse)); // {"message":"Hi","Works":true}
    Assert.That(jsonResponse, Is.InstanceOf<dynamic>());
    Assert.That(jsonResponse, Is.TypeOf<JObject>());
}

E, naturalmente, il modo migliore per ottenere la versione corrente è tramite NuGet.

Aggiornato (11/12/2014) per rispondere ai commenti:

Funziona perfettamente. Se si controlla il tipo nel debugger, si vedrà che il valore è, in effetti, dinamico . Il tipo sottostante è a JObject. Se vuoi controllare il tipo (come specificare ExpandoObject, quindi fallo.

inserisci qui la descrizione dell'immagine


20
Questo non sembra mai funzionare. Restituisce solo un JObject, non una variabile dinamica.
— Paul,

12
A proposito, questo funziona: JsonConvert.DeserializeObject <ExpandoObject> (STRING); con una corretta deserializzazione, quindi non abbiamo JObject ecc.
— Gutek,

2
@Gutek non sono sicuro di quale sia il tuo problema. Hai eseguito il codice? Ho aggiunto affermazioni al test e aggiunto una proprietà non nel json originale. Schermata del debugger inclusa.
— David Peden,

1
@DavidPeden se hai JObject e proverai a legare che in Razor otterrai eccezioni. La domanda era sulla deserializzazione di un oggetto dinamico - JObject è dinamico ma contiene tipi "propri" come JValue non tipi primitivi. Non riesco a usare il @Model.Propnome in Razor se il tipo restituito è JValue.
— Gutek,

2
Funziona, ma ogni proprietà dinamica è a JValue. Ciò mi ha confuso perché stavo lavorando nella finestra del debugger / immediato e non vedevo solo strings. David lo mostra nello screenshot in basso. Il JValueè convertibile in modo da poter fare solostring m = jsonResponse.message
— Luca Puplett

66

Se si deserializza in dinamico, si ottiene indietro un JObject. Puoi ottenere ciò che desideri utilizzando un ExpandoObject.

var converter = new ExpandoObjectConverter();    
dynamic message = JsonConvert.DeserializeObject<ExpandoObject>(jsonString, converter);

1
Il risultato può anche essere convertito in un dizionario
— FindOutIslamNow,

1
Esattamente quello che ho cercato! Grazie!
— DarkDeny,

42

So che questo è un vecchio post, ma JsonConvert ha in realtà un metodo diverso, quindi sarebbe

var product = new { Name = "", Price = 0 };
var jsonResponse = JsonConvert.DeserializeAnonymousType(json, product);

23
Ciò significherebbe deserializzare un payload json in un tipo anonimo, non in un tipo dinamico. I tipi anonimi e i tipi dinamici sono cose diverse e non credo che questo risolva la domanda posta.
— jrista,

1
È necessario utilizzare due variabili? Perché non riutilizzare il primo nella seconda affermazione?
— RenniePet,

21

Sì, puoi farlo utilizzando JsonConvert.DeserializeObject. Per farlo, fai semplicemente:

dynamic jsonResponse = JsonConvert.DeserializeObject(json);
Console.WriteLine(jsonResponse["message"]);

1
JsonConvertnon contiene un metodo chiamato Deserialize.
— Can Poyrazoğlu,

dovrebbe essere DeserializeObject, ma questa dovrebbe essere la risposta accettata IMO
— superjugy

21

Nota: Al momento in cui ho risposto a questa domanda nel 2010, non c'era modo di deserializzare senza una sorta di tipo, questo ti consentiva di deserializzare senza dover andare a definire la classe effettiva e di utilizzare una classe anonima per fare la deserializzazione.


Devi avere una sorta di tipo a cui deserializzare. Potresti fare qualcosa come:

var product = new { Name = "", Price = 0 };
dynamic jsonResponse = JsonConvert.Deserialize(json, product.GetType());

La mia risposta si basa su una soluzione per la build di .NET 4.0 nel serializzatore JSON. Il link per deserializzare i tipi anonimi è qui:

http://blogs.msdn.com/b/alexghi/archive/2008/12/22/using-anonymous-types-to-deserialize-json-data.aspx


Sono con te, phill, non so perché la gente vota in negativo questo, se qualcuno può, per favore, per favore, spiegare perché?
— PEO,

18
Stanno ridimensionando perché la domanda riguarda la deserializzazione senza un tipo.
— richard

4
La risposta era valida al momento della sua scrittura nel 2010 quando non esisteva altra soluzione. È stata persino la risposta accettata per un breve periodo di tempo fino a quando il supporto è arrivato in JSON.NET.
— Phill

1
Questo non produce un oggetto dinamico. Questo produce un JObject che si fa riferimento come dinamico. Ma è ancora un oggetto JO all'interno.
— ghostbust555,

5

Se usi JSON.NET con una versione precedente che non ha JObject.

Questo è un altro modo semplice per creare un oggetto dinamico da JSON: https://github.com/chsword/jdynamic

Installazione NuGet

PM> Install-Package JDynamic

Supporto per l'utilizzo dell'indice di stringa per accedere a membri come:

dynamic json = new JDynamic("{a:{a:1}}");
Assert.AreEqual(1, json["a"]["a"]);

Test Case

E puoi usare questo util come segue:

Ottieni direttamente il valore

dynamic json = new JDynamic("1");

//json.Value

2. Ottenere il membro nell'oggetto json

dynamic json = new JDynamic("{a:'abc'}");
//json.a is a string "abc"

dynamic json = new JDynamic("{a:3.1416}");
//json.a is 3.1416m

dynamic json = new JDynamic("{a:1}");
//json.a is integer: 1

3.IEnumerable

dynamic json = new JDynamic("[1,2,3]");
/json.Length/json.Count is 3
//And you can use json[0]/ json[2] to get the elements

dynamic json = new JDynamic("{a:[1,2,3]}");
//json.a.Length /json.a.Count is 3.
//And you can use  json.a[0]/ json.a[2] to get the elements

dynamic json = new JDynamic("[{b:1},{c:1}]");
//json.Length/json.Count is 2.
//And you can use the  json[0].b/json[1].c to get the num.

Altro

dynamic json = new JDynamic("{a:{a:1} }");

//json.a.a is 1.

2

Sì, è possibile. L'ho fatto per tutto il tempo.

dynamic Obj = JsonConvert.DeserializeObject(<your json string>);

È un po 'più complicato per il tipo non nativo. Supponiamo che all'interno di Obj ci siano oggetti ClassA e ClassB. Sono tutti convertiti in JObject. Quello che devi fare è:

ClassA ObjA = Obj.ObjA.ToObject<ClassA>();
ClassB ObjB = Obj.ObjB.ToObject<ClassB>();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.