Deserialice el objeto json en objeto dinámico usando Json.net

426

¿Es posible devolver un objeto dinámico de una deserialización de json usando json.net? Me gustaría hacer algo como esto:

dynamic jsonResponse = JsonConvert.Deserialize(json);
Console.WriteLine(jsonResponse.message);
ryudice
fuente
1
Considere generar la clase C # desde JSON json2csharp.com y use la clase generada en lugar de dinámica
Michael Freidgeim
¿Posible duplicado de Deserialize JSON en objeto dinámico C #?
meJustAndrew
¿Cómo sugieres que stackOverflow cierre una pregunta como "demasiado antigua"? Han pasado seis años, hay respuestas válidas y sugerencias razonables para cada versión de .net desde entonces ... tantas que ya no son realmente útiles.
Andrew lorien

Respuestas:

546

Json.NET nos permite hacer esto:

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

Salida:

 1000
 string
 6

Documentación aquí: LINQ to JSON con Json.NET

Ver también JObject.Parse y JArray.Parse

Michael Pakhantsov
fuente
36
Tenga en cuenta que para las matrices la sintaxis es JArray.Parse.
jgillich
44
¿Por qué necesitamos usar palabras dinámicas?
Tengo
3
En VB.Net debe hacerloDim d As Object = JObject.Parse("{number:1000, str:'string', array: [1,2,3,4,5,6]}")
ilans
2
@MonsterMMORPG Deberías ser :) Dinámico es un anti patrón en casi todas las circunstancias, pero, de vez en cuando, puedes tener una situación en la que es razonable usarlo.
Pluc
44
Con Newtonsoft.Json 8.0.3 (.NET 4.5.2): Microsoft.CSharp.RuntimeBinder.RuntimeBinderException ocurrió HResult = -2146233088 Mensaje = 'Newtonsoft.Json.Linq.JObject' no contiene una definición para 'número' Fuente = Microsoft .CSharp StackTrace: en Microsoft.CSharp.RuntimeBinder.RuntimeBinderController.SubmitError (CError pError)
user4698855
107

A partir de Json.NET 4.0 Release 1, hay soporte dinámico 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>());
}

Y, por supuesto, la mejor manera de obtener la versión actual es a través de NuGet.

Actualizado (12/11/2014) para abordar los comentarios:

Esto funciona perfectamente bien. Si inspecciona el tipo en el depurador, verá que el valor es, de hecho, dinámico . El tipo subyacente es a JObject. Si desea controlar el tipo (como especificar ExpandoObject, hágalo).

ingrese la descripción de la imagen aquí

David Peden
fuente
20
Esto nunca parece funcionar. Solo devuelve un JObject, no una variable dinámica.
Paul
12
Por cierto, esto funciona: JsonConvert.DeserializeObject <ExpandoObject> (STRING); con la deserialización adecuada, por lo que no tenemos JObject, etc.
Gutek
2
@Gutek no está seguro de cuál es su problema. ¿Ejecutó el código? Agregué afirmaciones a la prueba y agregué una propiedad que no estaba en el json original. Captura de pantalla del depurador incluido.
David Peden
1
@DavidPeden si tiene JObject e intentará vincular que en Razor obtendrá excepciones. La pregunta era sobre deserializar a objeto dinámico: JObject es dinámico pero contiene tipos "propios" como JValue, no tipos primitivos. No puedo usar el @Model.Propnombre en Razor si el tipo de retorno es JValue.
Gutek
2
Esto funciona, pero cada propiedad dinámica es un JValue. Lo que me confundió porque estaba trabajando en el depurador / ventana inmediata y no estaba viendo solo strings. David muestra esto en la captura de pantalla inferior. El JValuees convertible, así que puedes hacerlostring m = jsonResponse.message
Luke Puplett
66

Si solo se deserializa a dinámico, obtendrá un JObject de regreso. Puede obtener lo que desea usando un ExpandoObject.

var converter = new ExpandoObjectConverter();    
dynamic message = JsonConvert.DeserializeObject<ExpandoObject>(jsonString, converter);
Joshua Peterson
fuente
1
El resultado también se puede convertir a un diccionario
FindOutIslamNow
1
¡Exactamente lo que buscaba! ¡Gracias!
DarkDeny
42

Sé que esta es una publicación antigua, pero JsonConvert en realidad tiene un método diferente, por lo que sería

var product = new { Name = "", Price = 0 };
var jsonResponse = JsonConvert.DeserializeAnonymousType(json, product);
epitka
fuente
23
Eso sería deserializar una carga útil json en un tipo anónimo, no dinámico. Los tipos anónimos y los tipos dinámicos son cosas diferentes, y no creo que esto aborde la pregunta formulada.
jrista
1
¿Es necesario usar dos variables? ¿Por qué no reutilizar el primero en la segunda declaración?
RenniePet
21

Sí, puede hacerlo utilizando JsonConvert.DeserializeObject. Para hacer eso, simplemente hazlo:

dynamic jsonResponse = JsonConvert.DeserializeObject(json);
Console.WriteLine(jsonResponse["message"]);
oteal
fuente
1
JsonConvertno contiene un método llamado Deserialize.
Can Poyrazoğlu
debería ser solo DeserializeObject, pero esta debería ser la respuesta aceptada IMO
superjugy
21

Nota: En el momento en que respondí esta pregunta en 2010, no había forma de deserializar sin algún tipo de tipo, esto le permitió deserializar sin tener que definir la clase real y permitió que se usara una clase anónima para hacer la deserialización.


Necesitas tener algún tipo de tipo para deserializar. Podrías hacer algo en la línea de:

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

Mi respuesta se basa en una solución para la compilación de .NET 4.0 en el serializador JSON. El enlace para deserializar a tipos anónimos está aquí:

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

Phill
fuente
Estoy con ustedes, pero no sé por qué las personas votan en contra de esto, si alguien puede, por favor ... explique por qué.
PEO
18
Están votando negativamente porque la pregunta es sobre la deserialización sin un tipo.
Richard
44
La respuesta era válida al momento de escribirla en 2010 cuando no había otra solución. Incluso fue la respuesta aceptada por un pequeño período de tiempo hasta que llegó el soporte en JSON.NET.
Phill
1
Esto no produce un objeto dinámico. Esto produce un JObject al que hace referencia como dinámico. Pero todavía es un JObject por dentro.
ghostbust555
5

Si usa JSON.NET con una versión anterior que no JObject.

Esta es otra forma simple de hacer un objeto dinámico desde JSON: https://github.com/chsword/jdynamic

Instalar NuGet

PM> Install-Package JDynamic

Admite el uso de índice de cadena para acceder a miembros como:

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

Caso de prueba

Y puede usar esta utilidad de la siguiente manera:

Obtenga el valor directamente

dynamic json = new JDynamic("1");

//json.Value

2. Obtenga el miembro en el objeto 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 innumerable

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.

Otro

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

//json.a.a is 1.
chsword
fuente
2

Sí, es posible. He estado haciendo eso todo el tiempo.

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

Es un poco más complicado para el tipo no nativo. Supongamos que dentro de su Obj, hay un objeto ClassA y ClassB. Todos se convierten a JObject. Lo que debes hacer es:

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