¿Hay alguna manera de deserializar el contenido JSON en un tipo dinámico C # 4? Sería bueno omitir la creación de un montón de clases para usar el DataContractJsonSerializer.
Si quieres algo 'dinámico', ¿por qué no usar los accesos get-style que vienen con la mayoría de los decodificadores JSON que no van a objetos simples y antiguos? (por ejemplo, ¿existe realmente la necesidad de crear objetos 'dinámicos'?) json.org tiene un montón de enlaces para implementaciones de C # JSON.
Estoy trabajando en un proyecto que intenta mantener las dependencias externas al mínimo. Entonces, si es posible hacer algo con los serializadores .net y los tipos de acciones que serían preferidos. Por supuesto, si no es posible, estoy llamando a json.org. ¡Gracias!
jswanson
42
Estoy realmente sorprendido de que el equipo de C # haya agregado "dinámico", pero luego no hay forma en el CLR de convertir un objeto JSON en una instancia de clase CLR dinámica.
Frank Schwieterman
2
Lamentablemente, la respuesta aceptada no funciona en .NET 4 RTM. Publiqué una respuesta que me ayudó a ponerme en marcha, lo que podría ser útil para otros.
Drew Noakes
(Aunque parece que Newtonsoft JSON.NET se acerca bastante. Sin embargo, no hay ejemplos realmente buenos).
Hot Licks
Respuestas:
660
Si está contento de tener una dependencia en el System.Web.Helpersensamblado, puede usar la Jsonclase:
dynamic data =Json.Decode(json);
Se incluye con el marco MVC como una descarga adicional al marco .NET 4. ¡Asegúrate de darle un voto a Vlad si eso es útil! Sin embargo, si no puede asumir que el entorno del cliente incluye esta DLL, siga leyendo.
Aquí se sugiere un enfoque alternativo de deserialización . Modifiqué un poco el código para corregir un error y adaptarme a mi estilo de codificación. Todo lo que necesita es este código y una referencia System.Web.Extensionsde su proyecto:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;publicsealedclassDynamicJsonConverter:JavaScriptConverter{publicoverrideobjectDeserialize(IDictionary<string,object> dictionary,Type type,JavaScriptSerializer serializer){if(dictionary ==null)thrownewArgumentNullException("dictionary");return type ==typeof(object)?newDynamicJsonObject(dictionary):null;}publicoverrideIDictionary<string,object>Serialize(object obj,JavaScriptSerializer serializer){thrownewNotImplementedException();}publicoverrideIEnumerable<Type>SupportedTypes{get{returnnewReadOnlyCollection<Type>(newList<Type>(new[]{typeof(object)}));}}#region Nested type: DynamicJsonObjectprivatesealedclassDynamicJsonObject:DynamicObject{privatereadonlyIDictionary<string,object> _dictionary;publicDynamicJsonObject(IDictionary<string,object> dictionary){if(dictionary ==null)thrownewArgumentNullException("dictionary");
_dictionary = dictionary;}publicoverridestringToString(){var sb =newStringBuilder("{");ToString(sb);return sb.ToString();}privatevoidToString(StringBuilder sb){var firstInDictionary =true;foreach(var pair in _dictionary){if(!firstInDictionary)
sb.Append(",");
firstInDictionary =false;varvalue= pair.Value;var name = pair.Key;if(valueisstring){
sb.AppendFormat("{0}:\"{1}\"", name,value);}elseif(valueisIDictionary<string,object>){newDynamicJsonObject((IDictionary<string,object>)value).ToString(sb);}elseif(valueisArrayList){
sb.Append(name +":[");var firstInArray =true;foreach(var arrayValue in(ArrayList)value){if(!firstInArray)
sb.Append(",");
firstInArray =false;if(arrayValue isIDictionary<string,object>)newDynamicJsonObject((IDictionary<string,object>)arrayValue).ToString(sb);elseif(arrayValue isstring)
sb.AppendFormat("\"{0}\"", arrayValue);else
sb.AppendFormat("{0}", arrayValue);}
sb.Append("]");}else{
sb.AppendFormat("{0}:{1}", name,value);}}
sb.Append("}");}publicoverrideboolTryGetMember(GetMemberBinder binder,outobject result){if(!_dictionary.TryGetValue(binder.Name,out result)){// return null to avoid exception. caller can check for null this way...
result =null;returntrue;}
result =WrapResultObject(result);returntrue;}publicoverrideboolTryGetIndex(GetIndexBinder binder,object[] indexes,outobject result){if(indexes.Length==1&& indexes[0]!=null){if(!_dictionary.TryGetValue(indexes[0].ToString(),out result)){// return null to avoid exception. caller can check for null this way...
result =null;returntrue;}
result =WrapResultObject(result);returntrue;}returnbase.TryGetIndex(binder, indexes,out result);}privatestaticobjectWrapResultObject(object result){var dictionary = result asIDictionary<string,object>;if(dictionary !=null)returnnewDynamicJsonObject(dictionary);var arrayList = result asArrayList;if(arrayList !=null&& arrayList.Count>0){return arrayList[0]isIDictionary<string,object>?newList<object>(arrayList.Cast<IDictionary<string,object>>().Select(x =>newDynamicJsonObject(x))):newList<object>(arrayList.Cast<object>());}return result;}}#endregion}
Me sale un error en obj dinámico = serializador. Deserializar (json, typeof (objeto)); diciendo que no hay sobrecarga para el método con 2 argumentos ... dll incorrecto o qué?
Stewie Griffin
32
Puede usar System.Web.Helpers.Json: ofrece un método de decodificación que devuelve un objeto dinámico. También publiqué esta información como respuesta.
Vlad Iliescu
2
Esto también me ayudó mucho, pero tengo curiosidad por saber qué debo hacer si necesito usar el método .Serialize, que actualmente solo arroja una excepción NotImplementedException ... No estoy demasiado familiarizado con las clases selladas y / o el resumen extendido clases ¿Alguien puede señalarme en la dirección correcta?
Cory
2
a veces en js tienes campos con caracteres especiales como "color de fondo". Para acceder a dichos campos en js debe hacer obj ["color de fondo"]. ¿Cómo puedo acceder a dichos campos desde c # después de deserializar a objeto dinámico? No puedo hacer obj.background-color, por supuesto, y obj ["background-color"] no parece funcionar. Sería bueno si también se pudiera acceder al objeto dinámico como un diccionario, al mismo tiempo, exactamente como en js.
Radu Simionescu
2
@RaduSimionescu Probablemente llego un poco tarde, pero tal vez esto ayude a los futuros visitantes. Tuve el mismo problema, solo con el nombre del campo params(que es una palabra clave en C #). Además TryGetMember, puede anular TryGetIndex, lo que le proporciona exactamente el mismo comportamiento que en JS. Entonces puede hacer obj["params"]o obj["background-color"]para nombres de campo incómodos.
@HotLicks: para introspectar la dinámica, stuffhaga algo como:foreach (Newtonsoft.Json.Linq.JProperty jproperty in stuff) { Console.WriteLine("jproperty.Name = {0}", jproperty.Name);}
Matthias
11
¿Cuál es la diferencia entre JsonConvert.DeserializeObject y JObject.Parse? La respuesta es usarlos a ambos de la misma manera para hacer lo mismo, pero no explica la diferencia.
cja
77
@TomPeplow Probé esto. No me funcionó. Dice que "JObject no implementa 'Nombre'".
No puedo hacer que esto funcione. He reducido el problema a estar dentro de un asyncmétodo. Si hago el método sincrónico, funciona como se esperaba. Sin embargo, crea el método asyncy no puedo obtener un dynamic, solo obtengo un object. El casting explícito no hace nada, solo me da un object. ¿Hay alguien más experimentando esto?
codeConcussion
295
Puede hacerlo utilizando System.Web.Helpers.Json : su método Decode devuelve un objeto dinámico que puede atravesar a su gusto.
Se incluye en el ensamblado System.Web.Helpers (.NET 4.0).
has intentado esto? Vuelve Dictionary<string,object>. A menos que me falte algo, su ejemplo no devuelve un objeto dinámico.
sergiopereira
18
Esto no funciona, solo devuelve un dict en forma de dinámica
mattmanser
55
@ Peter Long Creo que no he podido exponer mi caso claramente, querido amigo. Permítame intentar rectificar mi error. Sé lo que es una dinámica. Esto no le permite pasar un objeto JSON y usar d.code, tendría que hacer d ["código"]. Valor, que no es lo que la mayoría de las personas que encuentran esta respuesta quieren, ya sabemos cómo obtener el diccionario y convertirlo en dinámico es una pérdida total de tiempo. Respetuosamente no estoy de acuerdo, señor.
mattmanser 01 de
44
@mattmanser, we already know how to get the dictionary and casting it to a dynamic. No tiene que ser un dictionay. Json también tiene listas además del diccionario. Y también se pueden anidar listas y diccionarios. Mi código podría manejar todas estas situaciones. PERO su método NO puede.
Peter Long
44
@mattmanser tiene razón; es posible implementar IDynamicMetaObjectProvider(o usar, por ejemplo ExpandoObject) que pueda interceptar propiedades y buscarlas en un diccionario interno. Esto combinado con el uso de dynamicpermite código como d.codepara ser utilizado. No tiene sentido lanzar un diccionario a una dinámica.
Stephen Drew el
78
"Datos JSON de cadena" simples para objetar sin ningún archivo DLL de terceros:
WebClient client =newWebClient();string getString = client.DownloadString("https://graph.facebook.com/zuck");JavaScriptSerializer serializer =newJavaScriptSerializer();dynamic item = serializer.Deserialize<object>(getString);string name = item["name"];//note: JavaScriptSerializer in this namespaces//System.Web.Script.Serialization.JavaScriptSerializer
No lo entiendo. Esta es, con mucho, la solución más simple y nadie lo menciona.
cikatomo
2
sí, es simple :) en algún momento necesitas serializar pero no quieres incluir la tercera parte dll
İbrahim Özbölük
¿Puede dar más detalles sobre: qué tan dinámico puede acceder al objeto serializado a través de myObject["myprop"]:? Sé que se realiza en tiempo de ejecución, pero ¿cómo myObject["myprop"]es válido acceder a través de él ?
Royi Namir
1
Puedes deserializar tu objeto como Personel item = serializer.Deserialize <Personel> (getString); y si usas un objeto dinámico también puedes usar una matriz y todo es posible como todo objeto
İbrahim Özbölük
3
Para usar el espacio de nombres System.Web.Script.Serialization, su proyecto necesita una referencia a System.Web.Extensions.
StilgarISCA
28
JsonFx puede deserializar el contenido JSON en objetos dinámicos.
Serializar hacia / desde tipos dinámicos (predeterminado para .NET 4.0):
Hice una nueva versión del DynamicJsonConverter que usa objetos Expando. Utilicé objetos expando, porque quería serializar la dinámica nuevamente en JSON usando Json.NET.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Web.Script.Serialization;publicstaticclassDynamicJson{publicstaticdynamicParse(string json){JavaScriptSerializer jss =newJavaScriptSerializer();
jss.RegisterConverters(newJavaScriptConverter[]{newDynamicJsonConverter()});dynamic glossaryEntry = jss.Deserialize(json,typeof(object))asdynamic;return glossaryEntry;}classDynamicJsonConverter:JavaScriptConverter{publicoverrideobjectDeserialize(IDictionary<string,object> dictionary,Type type,JavaScriptSerializer serializer){if(dictionary ==null)thrownewArgumentNullException("dictionary");var result =ToExpando(dictionary);return type ==typeof(object)? result :null;}privatestaticExpandoObjectToExpando(IDictionary<string,object> dictionary){var result =newExpandoObject();var dic = result asIDictionary<String,object>;foreach(var item in dictionary){var valueAsDic = item.ValueasIDictionary<string,object>;if(valueAsDic !=null){
dic.Add(item.Key,ToExpando(valueAsDic));continue;}var arrayList = item.ValueasArrayList;if(arrayList !=null&& arrayList.Count>0){
dic.Add(item.Key,ToExpando(arrayList));continue;}
dic.Add(item.Key, item.Value);}return result;}privatestaticArrayListToExpando(ArrayList obj){ArrayList result =newArrayList();foreach(var item in obj){var valueAsDic = item asIDictionary<string,object>;if(valueAsDic !=null){
result.Add(ToExpando(valueAsDic));continue;}var arrayList = item asArrayList;if(arrayList !=null&& arrayList.Count>0){
result.Add(ToExpando(arrayList));continue;}
result.Add(item);}return result;}publicoverrideIDictionary<string,object>Serialize(object obj,JavaScriptSerializer serializer){thrownewNotImplementedException();}publicoverrideIEnumerable<Type>SupportedTypes{get{returnnewReadOnlyCollection<Type>(newList<Type>(new[]{typeof(object)}));}}}}
dynamic json =newJDynamic("{a:'abc'}");// json.a is a string "abc"dynamic json =newJDynamic("{a:3.1416}");// json.a is 3.1416mdynamic json =newJDynamic("{a:1}");// json.a isdynamic json =newJDynamic("[1,2,3]");/json.Length/json.Countis3// And you can use json[0]/ json[2] to get the elementsdynamic json =newJDynamic("{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 elementsdynamic json =newJDynamic("[{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.
Entonces solo necesita tener una declaración de uso para el espacio de nombres en el que definió la extensión (considere simplemente definirlos en System.Web.Script.Serialization ... otro truco es no usar un espacio de nombres, entonces no necesita el uso declaración en absoluto) y puede consumirlos así:
var serializer =newJavaScriptSerializer();varvalue= serializer.DeserializeDynamic("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");var name =(string)value.Name;// Jon Smithvar age =(int)value.Age;// 42var address =value.Address;var city =(string)address.City;// New Yorkvar state =(string)address.State;// NY
publicclassChild{publicstring name {get;set;}publicint age {get;set;}}publicclassPerson{publicstring name {get;set;}publicint age {get;set;}publicstring city {get;set;}publicList<Child>Childs{get;set;}}
using Newtonsoft.Json;
namespace GitRepositoryCreator.Common{classJObjects{publicstaticstringGet(object p_object){returnJsonConvert.SerializeObject(p_object);}internalstatic T Get<T>(string p_object){returnJsonConvert.DeserializeObject<T>(p_object);}}}
Puedes llamarlo así:
Person jsonClass =JObjects.Get<Person>(stringJson);string stringJson =JObjects.Get(jsonClass);
PD:
Si su nombre de variable JSON no es un nombre válido de C # (el nombre comienza con $), puede solucionarlo de esta manera:
Para eso, usaría JSON.NET para hacer el análisis de bajo nivel de la secuencia JSON y luego construir la jerarquía de objetos a partir de instancias de la ExpandoObjectclase.
pero esa no es la pregunta que se hace. Hay una diferencia cuando tienes que especificar el tipo para cada cadena json y trabajar con el tipo dinámico.
Illuminati
5
Mire el artículo que escribí en CodeProject, uno que responde a la pregunta con precisión:
¡Esto me ahorró mucho tiempo! debe elegirse como mejor respuesta!
jsiot
4
La deserialización en JSON.NET puede ser dinámica utilizando la JObjectclase, que se incluye en esa biblioteca. Mi cadena JSON representa estas clases:
Ahora deserializamos la cadena SIN hacer referencia a las clases anteriores:
var dyn =JsonConvert.DeserializeObject<JObject>(jsonAsFooString);JProperty propAge = dyn.Properties().FirstOrDefault(i=>i.Name=="Age");if(propAge !=null){int age =int.Parse(propAge.Value.ToString());Console.WriteLine("age="+ age);}//or as a one-liner:int myage =int.Parse(dyn.Properties().First(i=>i.Name=="Age").Value.ToString());
O si quieres profundizar:
var propBar = dyn.Properties().FirstOrDefault(i=>i.Name=="Bar");if(propBar !=null){JObject o =(JObject)propBar.First();var propBDay = o.Properties().FirstOrDefault(i => i.Name=="BDay");if(propBDay !=null){DateTime bday =DateTime.Parse(propBDay.Value.ToString());Console.WriteLine("birthday="+ bday.ToString("MM/dd/yyyy"));}}//or as a one-liner:DateTime mybday =DateTime.Parse(((JObject)dyn.Properties().First(i=>i.Name=="Bar").First()).Properties().First(i=>i.Name=="BDay").Value.ToString());
Este enfoque permite "atravesar" el documento jSON, de modo que pueda administrar la situación en la que la estructura JSON es desconocida o variable (por ejemplo, muchas API devuelven un documento JSON completamente diferente cuando se produce un error). ¿Hay otras bibliotecas que permiten hacer eso, aparte de Newtonsoft.JSON (también conocido como JSON.NET)?
Alex 75
4
El objeto que desea DynamicJSONObject se incluye en System.Web.Helpers.dll del paquete de páginas web ASP.NET, que forma parte de WebMatrix.
Use DataSet (C #) con JavaScript. Una función simple para crear una secuencia JSON con entrada de DataSet. Cree contenido JSON como (conjunto de datos de varias tablas):
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;Container container =JsonConvert.Deserialize<Container>(jsonAsString,newExpandoObjectConverter());
var jsonString =(File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(),"delete_result.json")));var objects =JsonConvert.DeserializeObject<dynamic>(jsonString);foreach(var o in objects){Console.WriteLine($"{o.id.ToString()}");}
Respuestas:
Si está contento de tener una dependencia en el
System.Web.Helpers
ensamblado, puede usar laJson
clase:Se incluye con el marco MVC como una descarga adicional al marco .NET 4. ¡Asegúrate de darle un voto a Vlad si eso es útil! Sin embargo, si no puede asumir que el entorno del cliente incluye esta DLL, siga leyendo.
Aquí se sugiere un enfoque alternativo de deserialización . Modifiqué un poco el código para corregir un error y adaptarme a mi estilo de codificación. Todo lo que necesita es este código y una referencia
System.Web.Extensions
de su proyecto:Puedes usarlo así:
Entonces, dada una cadena JSON:
El siguiente código funcionará en tiempo de ejecución:
fuente
params
(que es una palabra clave en C #). AdemásTryGetMember
, puede anularTryGetIndex
, lo que le proporciona exactamente el mismo comportamiento que en JS. Entonces puede hacerobj["params"]
oobj["background-color"]
para nombres de campo incómodos.Es bastante simple usar Json.NET :
También
using Newtonsoft.Json.Linq
:Documentación: Consultar JSON con dinámica
fuente
stuff
haga algo como:foreach (Newtonsoft.Json.Linq.JProperty jproperty in stuff) { Console.WriteLine("jproperty.Name = {0}", jproperty.Name);}
async
método. Si hago el método sincrónico, funciona como se esperaba. Sin embargo, crea el métodoasync
y no puedo obtener undynamic
, solo obtengo unobject
. El casting explícito no hace nada, solo me da unobject
. ¿Hay alguien más experimentando esto?Puede hacerlo utilizando System.Web.Helpers.Json : su método Decode devuelve un objeto dinámico que puede atravesar a su gusto.
Se incluye en el ensamblado System.Web.Helpers (.NET 4.0).
fuente
.NET 4.0 tiene una biblioteca incorporada para hacer esto:
Esta es la forma más simple.
fuente
Dictionary<string,object>
. A menos que me falte algo, su ejemplo no devuelve un objeto dinámico.we already know how to get the dictionary and casting it to a dynamic
. No tiene que ser un dictionay. Json también tiene listas además del diccionario. Y también se pueden anidar listas y diccionarios. Mi código podría manejar todas estas situaciones. PERO su método NO puede.IDynamicMetaObjectProvider
(o usar, por ejemploExpandoObject
) que pueda interceptar propiedades y buscarlas en un diccionario interno. Esto combinado con el uso dedynamic
permite código comod.code
para ser utilizado. No tiene sentido lanzar un diccionario a una dinámica."Datos JSON de cadena" simples para objetar sin ningún archivo DLL de terceros:
Nota: También puede usar su objeto personalizado.
fuente
myObject["myprop"]
:? Sé que se realiza en tiempo de ejecución, pero ¿cómomyObject["myprop"]
es válido acceder a través de él ?JsonFx puede deserializar el contenido JSON en objetos dinámicos.
fuente
Hice una nueva versión del DynamicJsonConverter que usa objetos Expando. Utilicé objetos expando, porque quería serializar la dinámica nuevamente en JSON usando Json.NET.
fuente
Otra forma de usar Newtonsoft.Json :
fuente
Puede lograr eso con la ayuda de Newtonsoft.Json. Instale Newtonsoft.Json desde Nuget y el:
fuente
La forma más simple es:
Simplemente incluya este archivo DLL .
Use el código como este:
fuente
Puede extender el JavaScriptSerializer para copiar recursivamente el diccionario que creó para expandir los objetos y luego usarlos dinámicamente:
Entonces solo necesita tener una declaración de uso para el espacio de nombres en el que definió la extensión (considere simplemente definirlos en System.Web.Script.Serialization ... otro truco es no usar un espacio de nombres, entonces no necesita el uso declaración en absoluto) y puede consumirlos así:
fuente
Puedes usar
using Newtonsoft.Json
resolvedEvent.Event.Data
es mi respuesta al llamar a Core Event.fuente
Uso http://json2csharp.com/ para obtener una clase que represente el objeto JSON.
Entrada:
Salida:
Después de eso uso Newtonsoft.Json para llenar la clase:
Puedes llamarlo así:
PD:
Si su nombre de variable JSON no es un nombre válido de C # (el nombre comienza con
$
), puede solucionarlo de esta manera:fuente
Para eso, usaría JSON.NET para hacer el análisis de bajo nivel de la secuencia JSON y luego construir la jerarquía de objetos a partir de instancias de la
ExpandoObject
clase.fuente
Estoy usando así en mi código y está funcionando bien
fuente
Mire el artículo que escribí en CodeProject, uno que responde a la pregunta con precisión:
Tipos dinámicos con JSON.NET
Hay demasiado para volver a publicarlo todo aquí, y menos aún porque ese artículo tiene un archivo adjunto con la clave / archivo fuente requerido.
fuente
Otra opción es "Pegar JSON como clases" para que se pueda deserializar de forma rápida y fácil.
Aquí hay una mejor explicación n piccas ... 'Pegar JSON como clases' en ASP.NET y Web Tools 2012.2 RC
fuente
La deserialización en JSON.NET puede ser dinámica utilizando la
JObject
clase, que se incluye en esa biblioteca. Mi cadena JSON representa estas clases:Ahora deserializamos la cadena SIN hacer referencia a las clases anteriores:
O si quieres profundizar:
Ver publicación para un ejemplo completo.
fuente
El objeto que desea DynamicJSONObject se incluye en System.Web.Helpers.dll del paquete de páginas web ASP.NET, que forma parte de WebMatrix.
fuente
Hay una biblioteca JSON liviana para C # llamada SimpleJson .
Es compatible con .NET 3.5+, Silverlight y Windows Phone 7.
Admite dinámica para .NET 4.0
También se puede instalar como un paquete NuGet
fuente
Use DataSet (C #) con JavaScript. Una función simple para crear una secuencia JSON con entrada de DataSet. Cree contenido JSON como (conjunto de datos de varias tablas):
Solo del lado del cliente, use eval. Por ejemplo,
Luego use:
fuente
Para obtener un Objeto de Expando:
fuente
Prueba esto:
fuente
Cómo analizar contenido JSON fácil con Dynamic & JavaScriptSerializer
Agregue la referencia de System.Web.Extensions y agregue este espacio
using System.Web.Script.Serialization;
de nombres en la parte superior:Cómo analizar JSON anidado y complejo con Dynamic y JavaScriptSerializer
Agregue la referencia de System.Web.Extensions y agregue este espacio
using System.Web.Script.Serialization;
de nombres en la parte superior:fuente
Con Cinchoo ETL , una biblioteca de código abierto disponible para analizar JSON en un objeto dinámico:
Salida:
Descargo de responsabilidad: soy el autor de esta biblioteca.
fuente
intenta de esta manera!
Ejemplo de JSON:
Código C #:
fuente