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

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


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


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


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

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

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

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


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.

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>();
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.