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.