Désérialiser un objet json en objet dynamique à l'aide de Json.net

426

Est-il possible de renvoyer un objet dynamique d'une désérialisation json en utilisant json.net? Je voudrais faire quelque chose comme ça:

dynamic jsonResponse = JsonConvert.Deserialize(json);
Console.WriteLine(jsonResponse.message);
ryudice
la source
1
Envisagez de générer une classe C # à partir de JSON json2csharp.com et utilisez la classe générée au lieu de dynamique
Michael Freidgeim
Duplication possible de Deserialize JSON en objet dynamique C #?
meJustAndrew
Comment proposez-vous à stackOverflow de fermer une question comme "trop ​​ancienne"? Cela fait six ans, il y a des réponses valides et des suggestions raisonnables pour chaque version de .net depuis lors ... tellement qu'elles ne sont plus vraiment utiles.
andrew lorien

Réponses:

547

Json.NET nous permet de faire ceci:

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

Production:

 1000
 string
 6

Documentation ici: LINQ to JSON avec Json.NET

Voir aussi JObject.Parse et JArray.Parse

Michael Pakhantsov
la source
36
Notez que pour les tableaux, la syntaxe est JArray.Parse.
jgillich
4
Pourquoi devons-nous utiliser un mot dynamique? j'ai peur jamais utilisé auparavant: D
MonsterMMORPG
3
Dans VB.Net, vous devez faireDim d As Object = JObject.Parse("{number:1000, str:'string', array: [1,2,3,4,5,6]}")
ilans
2
@MonsterMMORPG Vous devriez être :) Dynamic est un anti pattern dans presque toutes les circonstances, mais, de temps en temps, vous pouvez avoir une situation où il est raisonnable de l'utiliser.
Pluc
4
Avec Newtonsoft.Json 8.0.3 (.NET 4.5.2): Microsoft.CSharp.RuntimeBinder.RuntimeBinderException s'est produite HResult = -2146233088 Message = 'Newtonsoft.Json.Linq.JObject' ne contient pas de définition pour 'nombre' Source = Microsoft .CSharp StackTrace: sur Microsoft.CSharp.RuntimeBinder.RuntimeBinderController.SubmitError (CError pError)
user4698855
107

Depuis Json.NET 4.0 Release 1, il existe une prise en charge dynamique native:

[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>());
}

Et, bien sûr, la meilleure façon d'obtenir la version actuelle est via NuGet.

Mis à jour (11/12/2014) pour répondre aux commentaires:

Cela fonctionne parfaitement bien. Si vous inspectez le type dans le débogueur, vous verrez que la valeur est, en fait, dynamique . Le type sous-jacent est a JObject. Si vous souhaitez contrôler le type (comme spécifier ExpandoObject, faites-le.

entrez la description de l'image ici

David Peden
la source
20
Cela ne semble jamais fonctionner. Il ne renvoie qu'un JObject, pas une variable dynamique.
Paul
12
BTW, cela fonctionne: JsonConvert.DeserializeObject <ExpandoObject> (STRING); avec une désérialisation appropriée, nous n'avons donc pas JObject etc.
Gutek
2
@Gutek ne sais pas quel est votre problème. Avez-vous exécuté le code? J'ai ajouté des assertions au test et ajouté une propriété qui ne se trouve pas dans le json d'origine. Capture d'écran du débogueur incluse.
David Peden
1
@DavidPeden si vous avez JObject et que vous essayez de le lier dans Razor, vous obtiendrez des exceptions. La question portait sur la désérialisation en objet dynamique - JObject est dynamique mais contient des types "propres" comme JValue et non des types primitifs. Je ne peux pas utiliser de @Model.Propnom dans Razor si le type de retour est JValue.
Gutek
2
Cela fonctionne, mais chaque propriété dynamique est un JValue. Ce qui m'a dérouté parce que je travaillais dans le débogueur / fenêtre immédiate et que je ne voyais pas seulement l' stringart. David le montre dans la capture d'écran du bas. Le JValueest convertible pour que vous puissiez le fairestring m = jsonResponse.message
Luke Puplett
66

Si vous venez de désérialiser en dynamique, vous obtiendrez un JObject. Vous pouvez obtenir ce que vous voulez en utilisant un ExpandoObject.

var converter = new ExpandoObjectConverter();    
dynamic message = JsonConvert.DeserializeObject<ExpandoObject>(jsonString, converter);
Joshua Peterson
la source
1
Le résultat peut également être converti en dictionnaire
FindOutIslamNow
1
Exactement ce que je cherchais! Merci!
DarkDeny
42

Je sais que c'est un ancien poste, mais JsonConvert a en fait une méthode différente, donc ce serait

var product = new { Name = "", Price = 0 };
var jsonResponse = JsonConvert.DeserializeAnonymousType(json, product);
epitka
la source
23
Ce serait désérialiser une charge utile json en un type anonyme, pas un type dynamique. Les types anonymes et les types dynamiques sont des choses différentes, et je ne pense pas que cela réponde à la question posée.
jrista
1
Faut-il utiliser deux variables? Pourquoi ne pas réutiliser le premier dans la deuxième déclaration?
RenniePet
21

Oui, vous pouvez le faire à l'aide de JsonConvert.DeserializeObject. Pour ce faire, il suffit de faire simplement:

dynamic jsonResponse = JsonConvert.DeserializeObject(json);
Console.WriteLine(jsonResponse["message"]);
oteal
la source
1
JsonConvertne contient pas de méthode appelée Deserialize.
Can Poyrazoğlu
cela devrait être simplement DeserializeObject, mais cela devrait être la réponse acceptée IMO
superjugy
21

Remarque: Au moment où j'ai répondu à cette question en 2010, il n'y avait aucun moyen de désérialiser sans une sorte de type, cela vous a permis de désérialiser sans avoir à définir la classe réelle et a permis qu'une classe anonyme soit utilisée pour effectuer la désérialisation.


Vous devez avoir une sorte de type à désérialiser. Vous pourriez faire quelque chose comme:

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

Ma réponse est basée sur une solution pour la construction de .NET 4.0 dans le sérialiseur JSON. Le lien pour désérialiser vers les types anonymes est ici:

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

Phill
la source
Je suis avec toi phill ne sais pas pourquoi les gens votent contre cela, si quelqu'un peut vous plaire, veuillez expliquer pourquoi?
PEO
18
Ils sont downvoting parce que la question concerne la désérialisation sans type.
richard
4
La réponse était valable au moment de sa rédaction en 2010, alors qu'il n'y avait pas d'autre solution. C'était même la réponse acceptée pendant une petite période de temps jusqu'à ce que le support arrive dans JSON.NET.
Phill
1
Cela ne produit pas d'objet dynamique. Cela produit un JObject que vous référencez comme dynamique. Mais c'est toujours un JObject à l'intérieur.
ghostbust555
5

Si vous utilisez JSON.NET avec une ancienne version qui n'a pas JObject.

C'est une autre façon simple de créer un objet dynamique à partir de JSON: https://github.com/chsword/jdynamic

Installation de NuGet

PM> Install-Package JDynamic

Prise en charge de l'utilisation de l'index de chaîne pour accéder aux membres comme:

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

Cas de test

Et vous pouvez utiliser cet util comme suit:

Obtenez la valeur directement

dynamic json = new JDynamic("1");

//json.Value

Obtention du membre dans l'objet 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.Inombrable

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.

Autre

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

//json.a.a is 1.
chsword
la source
2

Oui c'est possible. Je le fais depuis toujours.

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

C'est un peu plus délicat pour le type non natif. Supposons qu'à l'intérieur de votre Obj, il y ait des objets ClassA et ClassB. Ils sont tous convertis en JObject. Ce que vous devez faire, c'est:

ClassA ObjA = Obj.ObjA.ToObject<ClassA>();
ClassB ObjB = Obj.ObjB.ToObject<ClassB>();
sk
la source