Existe uma maneira de desserializar o conteúdo JSON em um tipo dinâmico C # 4? Seria bom pular a criação de um monte de classes para usar o DataContractJsonSerializer.
Se você deseja algo 'dinâmico', por que não usar apenas os acessadores de estilo get que acompanham a maioria dos decodificadores JSON que não vão para objetos antigos simples? (por exemplo, existe realmente a necessidade de criação de objetos 'dinâmicos'?) O json.org possui vários links para implementações em C # JSON.
Estou trabalhando em um projeto que está tentando manter as dependências externas no mínimo. Portanto, se é possível encontrar algo com os serializadores .net e os tipos preferidos. Claro que, se não for possível, estou acessando o json.org. Obrigado!
jswanson
42
Estou realmente surpreso que a equipe de C # tenha adicionado 'dinâmico', mas não há como, no CLR, converter um objeto JSON em uma instância de classe dinâmica do CLR.
24510 Frank Schwieterman
2
Infelizmente, a resposta aceita não funciona no .NET 4 RTM. Publiquei uma resposta que me ajudou a seguir adiante, o que pode ser útil para outras pessoas.
Drew Noakes
(Embora pareça que Newtonsoft JSON.NET chega bem perto Não há qualquer realmente bons exemplos, no entanto..)
Hot Licks
Respostas:
659
Se você estiver feliz por ter uma dependência da System.Web.Helpersmontagem, poderá usar a Jsonclasse:
dynamic data =Json.Decode(json);
Ele está incluído na estrutura MVC como um download adicional para a estrutura .NET 4. Certifique-se de dar um voto positivo a Vlad, se isso for útil! No entanto, se você não puder assumir que o ambiente do cliente inclui esta DLL, continue a ler.
Uma abordagem alternativa de desserialização é sugerida aqui . Modifiquei o código levemente para corrigir um erro e se adequar ao meu estilo de codificação. Tudo o que você precisa é deste código e uma referência System.Web.Extensionsdo seu projeto:
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}
Eu recebo um erro no dinâmico obj = serializer.Deserialize (json, typeof (object)); dizendo que não há sobrecarga para o método com 2 argumentos..dll errado ou o quê?
Stewie Griffin
32
Você pode usar System.Web.Helpers.Json - ele oferece um método Decode que retorna um objeto dinâmico. Também publiquei essas informações como resposta.
Vlad Iliescu 29/02
2
Isso também me ajudou muito, mas estou curioso para saber o que devo fazer se precisar usar o método .Serialize, que atualmente gera apenas uma NotImplementedException ... Não estou familiarizado com classes seladas e / ou resumo estendido Aulas. Alguém pode me apontar na direção certa?
Cory W.
2
às vezes em js você tem campos com caracteres especiais como "background-color". Para acessar esses campos em js, você obj ["background-color"]. Como posso acessar esses campos de c # após desserializar para objeto dinâmico? Não posso fazer obj.background-color, é claro, e obj ["background-color"] parece não funcionar. Seria bom se o objeto dinâmico também pudesse ser acessado como um dicionário, ao mesmo tempo, exatamente como em js.
Radu Simionescu 28/09/12
2
@RaduSimionescu Provavelmente estou um pouco atrasado, mas talvez isso ajude futuros visitantes. Eu tive o mesmo problema, apenas com o nome do campo params(que é uma palavra-chave em c #). Além de TryGetMembervocê pode substituir TryGetIndex, o que fornece exatamente o mesmo comportamento que em JS. Então você pode fazer obj["params"]ou obj["background-color"]para nomes de campos estranhos.
@HotLicks: para a introspecção a dinâmica stufffazer algo como:foreach (Newtonsoft.Json.Linq.JProperty jproperty in stuff) { Console.WriteLine("jproperty.Name = {0}", jproperty.Name);}
Matthias
11
Qual é a diferença entre JsonConvert.DeserializeObject e JObject.Parse? A resposta é usá-los da mesma maneira para fazer a mesma coisa, mas não explica a diferença.
CJA
7
@TomPeplow Tentei isso. Não funcionou para mim. Ele diz que "JObject não implementa 'Nome'".
Não consigo fazer isso funcionar. Eu reduzi o problema para dentro de um asyncmétodo. Se eu tornar o método síncrono, ele funcionará conforme o esperado. No entanto, faça o método asynce não consigo obter um dynamic, apenas recebo um object. A transmissão explícita não faz nada, ainda me dá uma object. Alguém mais está experimentando isso?
codeConcussion
295
Você pode fazer isso usando System.Web.Helpers.Json - seu método Decode retorna um objeto dinâmico que você pode atravessar como quiser.
Está incluído no assembly System.Web.Helpers (.NET 4.0).
você já tentou isso? Retorna Dictionary<string,object>. A menos que esteja faltando alguma coisa, seu exemplo não retorna um objeto dinâmico.
sergiopereira 13/06
18
Isso não funciona, ele só retornar um dicionário na forma de uma dinâmica
mattmanser
55
@ Peter Long Eu acredito que falhei em declarar meu caso claramente, querido companheiro. Deixe-me tentar corrigir meu erro. Eu sei o que é uma dinâmica. Isso não permite que você passe um objeto JSON e use d.code, você teria que fazer d ["code"]. Value, que não é o que a maioria das pessoas que encontra essa resposta deseja, já sabemos como obter o dicionário e convertê-lo para uma dinâmica é uma total perda de tempo. Eu discordo respeitosamente, senhor.
mattmanser
4
@mattmanser we already know how to get the dictionary and casting it to a dynamic,. Não precisa ser um ditado. Json também tem listas além do dicionário. E também listas e dicionários podem ser aninhados. Meu código pode lidar com todas essas situações. MAS o seu método NÃO pode.
Peter Long
4
@mattmanser está certo; é possível implementar IDynamicMetaObjectProvider(ou usar, por exemplo ExpandoObject) capaz de interceptar propriedades e procurá-las em um dicionário interno. Isso combinado com o uso de dynamicpermite que códigos como d.codesejam usados. É meio inútil converter um dicionário em uma dinâmica.
Stephen Drew
78
Simples "string JSON data" para objetar sem nenhum arquivo DLL de terceiros:
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
Nota: Você também pode usar seu objeto personalizado.
Eu não entendi. Essa é de longe a solução mais simples e ninguém a menciona.
cikatomo
2
Sim, é simples :) algum momento você precisa serializar mas não quer incluir 3ª dll parte
İbrahim Özbölük
Você pode elaborar sobre: quão dinâmico pode acessar o objeto DEserialized via myObject["myprop"]:? Eu sei que é feito em tempo de execução, mas como o acesso myObject["myprop"]é válido?
Royi Namir 19/09/2013
1
Você pode desserializar seu objeto como item Personel = serializer.Deserialize <Personel> (getString); e se você usar objeto dinâmico também pode usar variedade e tudo é possível, como everyobject
İbrahim Özbölük
3
Para usar o espaço para nome System.Web.Script.Serialization, seu projeto precisa de uma referência a System.Web.Extensions.
perfil completo de Stilgar
28
O JsonFx pode desserializar o conteúdo JSON em objetos dinâmicos.
Serializar de / para tipos dinâmicos (padrão para .NET 4.0):
Eu fiz uma nova versão do DynamicJsonConverter que usa o Expando Objects. Eu usei expando objetos, porque queria serializar a dinâmica novamente no JSON usando o 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.
Então você só precisa ter uma instrução using para o namespace em que você definiu a extensão (considere defini-las em System.Web.Script.Serialization ... outro truque é não usar um namespace, então você não precisa usar ) e você pode consumi-los da seguinte maneira:
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;}}
Depois disso, uso o Newtonsoft.Json para preencher a classe:
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);}}}
Você pode chamar assim:
Person jsonClass =JObjects.Get<Person>(stringJson);string stringJson =JObjects.Get(jsonClass);
PS:
Se o nome da variável JSON não for um nome C # válido (o nome começa com $), você poderá corrigir isso assim:
Para isso, eu usaria o JSON.NET para fazer a análise de baixo nível do fluxo JSON e criar a hierarquia de objetos a partir das instâncias da ExpandoObjectclasse.
mas não é sobre isso que a pergunta está sendo feita. há um diferente quando você precisa especificar o tipo para cada string json e trabalhar com o tipo dinâmico.
Illuminati
5
Veja o artigo que escrevi no CodeProject, que responde com precisão à pergunta:
Agora desserializamos a string SEM referenciar as classes acima:
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());
Ou se você quiser ir mais fundo:
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());
Essa abordagem permite "atravessar" o documento jSON, para que você possa gerenciar situações em que a estrutura JSON é desconhecida ou variável (por exemplo, muitas API retornam um documento JSON completamente diferente quando ocorre um erro). Existem outras bibliotecas que permitem isso, além do Newtonsoft.JSON (também conhecido como JSON.NET)?
Alex 75
4
O objeto que você deseja DynamicJSONObject está incluído no System.Web.Helpers.dll do pacote ASP.NET Web Pages, que faz parte do WebMatrix.
Use DataSet (C #) com JavaScript. Uma função simples para criar um fluxo JSON com entrada DataSet. Crie conteúdo JSON como (conjunto de dados de várias tabelas):
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()}");}
Respostas:
Se você estiver feliz por ter uma dependência da
System.Web.Helpers
montagem, poderá usar aJson
classe:Ele está incluído na estrutura MVC como um download adicional para a estrutura .NET 4. Certifique-se de dar um voto positivo a Vlad, se isso for útil! No entanto, se você não puder assumir que o ambiente do cliente inclui esta DLL, continue a ler.
Uma abordagem alternativa de desserialização é sugerida aqui . Modifiquei o código levemente para corrigir um erro e se adequar ao meu estilo de codificação. Tudo o que você precisa é deste código e uma referência
System.Web.Extensions
do seu projeto:Você pode usá-lo assim:
Portanto, dada uma string JSON:
O código a seguir funcionará em tempo de execução:
fonte
params
(que é uma palavra-chave em c #). Além deTryGetMember
você pode substituirTryGetIndex
, o que fornece exatamente o mesmo comportamento que em JS. Então você pode fazerobj["params"]
ouobj["background-color"]
para nomes de campos estranhos.É bem simples usando o Json.NET :
Também
using Newtonsoft.Json.Linq
:Documentation: Consultando JSON com Dynamic
fonte
stuff
fazer algo como:foreach (Newtonsoft.Json.Linq.JProperty jproperty in stuff) { Console.WriteLine("jproperty.Name = {0}", jproperty.Name);}
async
método. Se eu tornar o método síncrono, ele funcionará conforme o esperado. No entanto, faça o métodoasync
e não consigo obter umdynamic
, apenas recebo umobject
. A transmissão explícita não faz nada, ainda me dá umaobject
. Alguém mais está experimentando isso?Você pode fazer isso usando System.Web.Helpers.Json - seu método Decode retorna um objeto dinâmico que você pode atravessar como quiser.
Está incluído no assembly System.Web.Helpers (.NET 4.0).
fonte
O .NET 4.0 possui uma biblioteca interna para fazer isso:
Esta é a maneira mais simples.
fonte
Dictionary<string,object>
. A menos que esteja faltando alguma coisa, seu exemplo não retorna um objeto dinâmico.we already know how to get the dictionary and casting it to a dynamic
,. Não precisa ser um ditado. Json também tem listas além do dicionário. E também listas e dicionários podem ser aninhados. Meu código pode lidar com todas essas situações. MAS o seu método NÃO pode.IDynamicMetaObjectProvider
(ou usar, por exemploExpandoObject
) capaz de interceptar propriedades e procurá-las em um dicionário interno. Isso combinado com o uso dedynamic
permite que códigos comod.code
sejam usados. É meio inútil converter um dicionário em uma dinâmica.Simples "string JSON data" para objetar sem nenhum arquivo DLL de terceiros:
Nota: Você também pode usar seu objeto personalizado.
fonte
myObject["myprop"]
:? Eu sei que é feito em tempo de execução, mas como o acessomyObject["myprop"]
é válido?O JsonFx pode desserializar o conteúdo JSON em objetos dinâmicos.
fonte
Eu fiz uma nova versão do DynamicJsonConverter que usa o Expando Objects. Eu usei expando objetos, porque queria serializar a dinâmica novamente no JSON usando o Json.NET.
fonte
Outra maneira de usar o Newtonsoft.Json :
fonte
Você pode conseguir isso com a ajuda do Newtonsoft.Json. Instale o Newtonsoft.Json a partir do Nuget e o:
fonte
A maneira mais simples é:
Basta incluir este arquivo DLL .
Use o código como este:
fonte
Você pode estender o JavaScriptSerializer para copiar recursivamente o dicionário criado para expandir o (s) objeto (s) e usá-los dinamicamente:
Então você só precisa ter uma instrução using para o namespace em que você definiu a extensão (considere defini-las em System.Web.Script.Serialization ... outro truque é não usar um namespace, então você não precisa usar ) e você pode consumi-los da seguinte maneira:
fonte
Você pode usar
using Newtonsoft.Json
resolvedEvent.Event.Data
é a minha resposta ao chamar o evento principal.fonte
Eu uso http://json2csharp.com/ para obter uma classe representando o objeto JSON.
Entrada:
Resultado:
Depois disso, uso o Newtonsoft.Json para preencher a classe:
Você pode chamar assim:
PS:
Se o nome da variável JSON não for um nome C # válido (o nome começa com
$
), você poderá corrigir isso assim:fonte
Para isso, eu usaria o JSON.NET para fazer a análise de baixo nível do fluxo JSON e criar a hierarquia de objetos a partir das instâncias da
ExpandoObject
classe.fonte
Estou usando assim no meu código e está funcionando bem
fonte
Veja o artigo que escrevi no CodeProject, que responde com precisão à pergunta:
Tipos dinâmicos com JSON.NET
Há muito para republicar tudo aqui, e menos ainda, pois esse artigo tem um anexo com o arquivo de origem chave / necessário.
fonte
Outra opção é "Colar JSON como classes" para que possa ser desserializado de maneira rápida e fácil.
Aqui está uma explicação melhor n piccas ... 'Colar JSON como classes' no ASP.NET e na Web Tools 2012.2 RC
fonte
A desserialização no JSON.NET pode ser dinâmica usando a
JObject
classe, incluída nessa biblioteca. Minha string JSON representa estas classes:Agora desserializamos a string SEM referenciar as classes acima:
Ou se você quiser ir mais fundo:
Veja a publicação para um exemplo completo.
fonte
O objeto que você deseja DynamicJSONObject está incluído no System.Web.Helpers.dll do pacote ASP.NET Web Pages, que faz parte do WebMatrix.
fonte
Existe uma biblioteca JSON leve para C # chamada SimpleJson .
Ele suporta .NET 3.5+, Silverlight e Windows Phone 7.
Ele suporta dinâmico para .NET 4.0
Também pode ser instalado como um pacote NuGet
fonte
Use DataSet (C #) com JavaScript. Uma função simples para criar um fluxo JSON com entrada DataSet. Crie conteúdo JSON como (conjunto de dados de várias tabelas):
Apenas do lado do cliente, use eval. Por exemplo,
Então use:
fonte
Para obter um ExpandoObject:
fonte
Tente o seguinte:
fonte
Como analisar conteúdo JSON fácil com dinâmico e JavaScriptSerializer
Adicione a referência de System.Web.Extensions e adicione este espaço
using System.Web.Script.Serialization;
para nome na parte superior:Como analisar json aninhado e complexo com dynamic & JavaScriptSerializer
Adicione a referência de System.Web.Extensions e adicione este espaço
using System.Web.Script.Serialization;
para nome na parte superior:fonte
Com o Cinchoo ETL - uma biblioteca de código aberto disponível para analisar o JSON em um objeto dinâmico:
Resultado:
Disclaimer: Eu sou o autor desta biblioteca.
fonte
tente assim!
Exemplo JSON:
Código c #:
fonte