Desserialize o objeto json em objeto dinâmico usando Json.net

426

É possível retornar um objeto dinâmico de uma desserialização json usando json.net? Eu gostaria de fazer algo assim:

dynamic jsonResponse = JsonConvert.Deserialize(json);
Console.WriteLine(jsonResponse.message);
Ryudice
fonte
1
Considere para gerar C # classe de JSON json2csharp.com e usar classe gerada ao invés de dinâmica
Michael Freidgeim
Possível duplicata de desserializar JSON em objeto dinâmico de C #?
precisa saber é o seguinte
Como você sugere que o stackOverflow feche uma pergunta como "muito antiga"? Faz seis anos, há respostas válidas e sugestões razoáveis ​​para todas as versões do .net desde então ... tantas que não são mais úteis.
andrew lorien

Respostas:

546

O Json.NET nos permite fazer isso:

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

Resultado:

 1000
 string
 6

Documentação aqui: LINQ to JSON com Json.NET

Consulte também JObject.Parse e JArray.Parse

Michael Pakhantsov
fonte
36
Observe que para matrizes a sintaxe é JArray.Parse.
Jgillich 15/05
4
Por que precisamos usar a palavra dinâmica? Estou com medo de nunca ter usado antes: D
MonsterMMORPG
3
No VB.Net você precisa fazer #Dim d As Object = JObject.Parse("{number:1000, str:'string', array: [1,2,3,4,5,6]}")
ilans
2
@MonsterMMORPG Você deveria ser :) Dinâmico é um anti-padrão em quase todas as circunstâncias, mas, de vez em quando, você pode ter uma situação em que é razoável usá-lo.
Pluc 18/03/16
4
Com Newtonsoft.Json 8.0.3 (.NET 4.5.2): Microsoft.CSharp.RuntimeBinder.RuntimeBinderException ocorreu HResult = -2146233088 Mensagem = 'Newtonsoft.Json.Linq.JObject' não contém uma definição para 'number' Source = Microsoft .CSharp StackTrace: no Microsoft.CSharp.RuntimeBinder.RuntimeBinderController.SubmitError (CError pError)
user4698855
107

A partir do Json.NET 4.0 Release 1, há suporte 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>());
}

E, é claro, a melhor maneira de obter a versão atual é via NuGet.

Atualizado (11/12/2014) para tratar dos comentários:

Isso funciona perfeitamente bem. Se você inspecionar o tipo no depurador, verá que o valor é de fato dinâmico . O tipo subjacente é a JObject. Se você deseja controlar o tipo (como especificar ExpandoObject, faça-o).

insira a descrição da imagem aqui

David Peden
fonte
20
Isso nunca parece funcionar. Ele retorna apenas um JObject, não uma variável dinâmica.
Paul
12
BTW, isso funciona: JsonConvert.DeserializeObject <ExpandoObject> (STRING); com desserialização adequada, para que não tenhamos JObject etc.
Gutek
2
@Gutek não sabe qual é o seu problema. Você executou o código? Adicionei declarações ao teste e adicionei uma propriedade que não está no json original. Captura de tela do depurador incluída.
22814 David Peden
1
@DavidPeden se você tiver JObject e tentará vincular isso no Razor, obterá exceções. A pergunta era sobre desserialização para objeto dinâmico - JObject é dinâmico, mas contém tipos "próprios", como JValue, e não tipos primitivos. Não posso usar o @Model.Propnome no Razor se o tipo de retorno for JValue.
Gutek
2
Isso funciona, mas cada propriedade dinâmica é a JValue. O que me confundiu porque eu estava trabalhando na janela do depurador / janela imediata e não estava vendo apenas strings. David mostra isso na captura de tela inferior. A JValueé conversível para que você pode apenas fazerstring m = jsonResponse.message
Luke Puplett
66

Se você apenas desserializar para dinâmico, receberá um JObject de volta. Você pode obter o que deseja usando um ExpandoObject.

var converter = new ExpandoObjectConverter();    
dynamic message = JsonConvert.DeserializeObject<ExpandoObject>(jsonString, converter);
Joshua Peterson
fonte
1
O resultado também pode ser convertido em um dicionário
FindOutIslamNow
1
Exatamente o que eu procurava! Obrigado!
DarkDeny 2/08/19
42

Eu sei que esse post é antigo, mas o JsonConvert realmente tem um método diferente, então seria

var product = new { Name = "", Price = 0 };
var jsonResponse = JsonConvert.DeserializeAnonymousType(json, product);
epitka
fonte
23
Isso seria desserializar uma carga útil do json para um tipo anônimo, não dinâmico. Tipos anônimos e tipos dinâmicos são coisas diferentes, e não acredito que isso atenda à pergunta.
jrista
1
É necessário usar duas variáveis? Por que não reutilizar o primeiro na segunda declaração?
RenniePet
21

Sim, você pode fazer isso usando o JsonConvert.DeserializeObject. Para fazer isso, basta fazer:

dynamic jsonResponse = JsonConvert.DeserializeObject(json);
Console.WriteLine(jsonResponse["message"]);
oteal
fonte
1
JsonConvertnão contém um método chamado Deserialize.
Can Poyrazoğlu
ele deve ser apenas DeserializeObject, mas isso deve ser a resposta aceita IMO
superjugy
21

Nota: No momento em que respondi a essa pergunta em 2010, não havia como desserializar sem algum tipo, isso permitiu que você desserializasse sem precisar definir a classe real e permitir que uma classe anônima fosse usada para fazer a desserialização.


Você precisa ter algum tipo de tipo para desserializar. Você poderia fazer algo como:

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

Minha resposta é baseada em uma solução para compilação do .NET 4.0 no serializador JSON. O link para desserializar para tipos anônimos está aqui:

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

Phill
fonte
Estou com você e não sei por que as pessoas votam menos, se alguém pode, por favor .. por favor, explique por quê?
PEO
18
Eles estão com voto negativo porque a questão é desserializar sem um tipo.
Richard
4
A resposta era válida no momento em que foi escrita em 2010, quando não havia outra solução. Foi até a resposta aceita por um pequeno período de tempo até o suporte no JSON.NET.
6776 Phill
1
Isso não produz um objeto dinâmico. Isso produz um JObject que você faz referência como dinâmica. Mas ainda é um objeto dentro.
ghostbust555
5

Se você usa o JSON.NET com a versão antiga que não JObject.

Esta é outra maneira simples de criar um objeto dinâmico a partir do JSON: https://github.com/chsword/jdynamic

Instalação do NuGet

PM> Install-Package JDynamic

Suporte usando o índice de string para acessar membros como:

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

Caso de teste

E você pode usar este utilitário da seguinte maneira:

Obtenha o valor diretamente

dynamic json = new JDynamic("1");

//json.Value

2.Obtenha o membro no 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.IEnumerable

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.

De outros

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

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

Sim, é possível. Eu tenho feito isso o tempo todo.

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

É um pouco mais complicado para o tipo não nativo. Suponha que dentro do seu Obj, haja objetos ClassA e ClassB. Todos eles são convertidos em JObject. O que você precisa fazer é:

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