Deserializuj obiekt json w obiekt dynamiczny za pomocą Json.net

426

Czy możliwe jest zwrócenie obiektu dynamicznego z deserializacji json przy użyciu json.net? Chciałbym zrobić coś takiego:

dynamic jsonResponse = JsonConvert.Deserialize(json);
Console.WriteLine(jsonResponse.message);
ryudice
źródło
1
Rozważ wygenerowanie klasy C # z JSON json2csharp.com i użyj wygenerowanej klasy zamiast dynamicznej
Michael Freidgeim
Możliwy duplikat deserializacji JSON w obiekt dynamiczny C #?
meJustAndrew
Jak sugerujesz stackOverflow zamknąć pytanie jako „za stare”? Minęło sześć lat, od tego czasu istnieją prawidłowe odpowiedzi i rozsądne sugestie dla każdej wersji .net ... tak wiele, że nie są już tak naprawdę pomocne.
andrew lorien

Odpowiedzi:

546

Json.NET pozwala nam to zrobić:

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

Wynik:

 1000
 string
 6

Dokumentacja tutaj: LINQ do JSON z Json.NET

Zobacz także JObject.Parse i JArray.Parse

Michael Pakhantsov
źródło
36
Zauważ, że dla tablic składnia jest następująca JArray.Parse.
jgillich
4
Dlaczego musimy używać dynamicznego słowa? boję się, że nigdy wcześniej nie był używany: D
MonsterMMORPG
3
W VB.Net musisz to zrobićDim d As Object = JObject.Parse("{number:1000, str:'string', array: [1,2,3,4,5,6]}")
ilans
2
@MonsterMMORPG Powinieneś być :) Dynamiczny jest anty-wzorcem w prawie każdych okolicznościach, ale od czasu do czasu możesz mieć sytuację, w której uzasadnione jest jego użycie.
Pluc
4
W przypadku Newtonsoft.Json 8.0.3 (.NET 4.5.2): Wystąpił wyjątek Microsoft.CSharp.RuntimeBinder.RuntimeBinderException HResult = -2146233088 Komunikat = „Newtonsoft.Json.Linq.JObject” nie zawiera definicji „liczby” Źródło = Microsoft .CSharp StackTrace: at Microsoft.CSharp.RuntimeBinder.RuntimeBinderController.SubmitError (CError pError)
user4698855
107

Począwszy od wersji Json.NET 4.0 wydanie 1, dostępna jest natywna obsługa dynamiczna:

[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>());
}

I oczywiście najlepszym sposobem na uzyskanie aktualnej wersji jest NuGet.

Zaktualizowano (11.12.2014) w celu uwzględnienia komentarzy:

Działa to doskonale. Jeśli sprawdzisz typ w debuggerze, zobaczysz, że wartość jest w rzeczywistości dynamiczna . Typu bazowego jest JObject. Jeśli chcesz kontrolować typ (np. Określanie ExpandoObject, zrób to).

wprowadź opis zdjęcia tutaj

David Peden
źródło
20
To nigdy nie działa. Zwraca tylko obiekt JObject, a nie zmienną dynamiczną.
Paul
12
BTW, to działa: JsonConvert.DeserializeObject <ExpandoObject> (STRING); z odpowiednią deserializacją, więc nie mamy JObject itp.
Gutek,
2
@ Gutek nie jest pewien, jaki jest Twój problem. Uruchomiłeś kod? Dodałem twierdzenia do testu i dodałem właściwość spoza oryginalnego jsona. Dołączony zrzut ekranu debuggera.
David Peden,
1
@DavidPeden, jeśli masz JObject i spróbujesz powiązać to w Razor, otrzymasz wyjątki. Pytanie dotyczyło deserializacji do obiektu dynamicznego - JObject jest dynamiczny, ale zawiera typy „własne”, takie jak JValue, a nie typy pierwotne. Nie mogę użyć @Model.Propnazwy w Razor, jeśli typem zwrotu jest JValue.
Gutek
2
To działa, ale każda właściwość dynamiczna to JValue. Co mnie zdezorientowało, ponieważ pracowałem w oknie debuggera / bezpośredniego i nie widziałem tylko strings. David pokazuje to na dolnym zrzucie ekranu. JValueJest wymienialna, dzięki czemu można po prostu zrobićstring m = jsonResponse.message
Luke Puplett
66

Jeśli deserializujesz tylko dynamicznie, odzyskasz JObject. Możesz uzyskać to, czego chcesz, korzystając z ExpandoObject.

var converter = new ExpandoObjectConverter();    
dynamic message = JsonConvert.DeserializeObject<ExpandoObject>(jsonString, converter);
Joshua Peterson
źródło
1
Wynik można również przekonwertować na słownik
FindOutIslamNow
1
Dokładnie to, czego szukałem! Dzięki!
DarkDeny,
42

Wiem, że to stary post, ale JsonConvert ma inną metodę, więc tak by było

var product = new { Name = "", Price = 0 };
var jsonResponse = JsonConvert.DeserializeAnonymousType(json, product);
epitka
źródło
23
Byłoby to deserializacją ładunku JSON na typ anonimowy, a nie typ dynamiczny. Typy anonimowe i typy dynamiczne to różne rzeczy i nie sądzę, że dotyczy to postawionego pytania.
jrista
1
Czy konieczne jest użycie dwóch zmiennych? Dlaczego nie wykorzystać ponownie pierwszego z drugiego oświadczenia?
RenniePet
21

Tak, możesz to zrobić za pomocą JsonConvert.DeserializeObject. Aby to zrobić, po prostu wykonaj:

dynamic jsonResponse = JsonConvert.DeserializeObject(json);
Console.WriteLine(jsonResponse["message"]);
oteal
źródło
1
JsonConvertnie zawiera metody o nazwie Deserialize.
Can Poyrazoğlu,
powinien to być po prostu DeserializeObject, ale taka powinna być zaakceptowana odpowiedź IMO
superjugy
21

Uwaga: w czasie, gdy odpowiedziałem na to pytanie w 2010 r., Nie było sposobu na deserializację bez jakiegoś rodzaju, pozwoliło to na deserializację bez konieczności definiowania rzeczywistej klasy i pozwoliło na użycie anonimowej klasy do przeprowadzenia deserializacji.


Musisz mieć jakiś typ do deserializacji. Możesz zrobić coś w stylu:

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

Moja odpowiedź oparta jest na rozwiązaniu do .NET 4.0 w wersji serializatora JSON. Link do deserializacji do typów anonimowych znajduje się tutaj:

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

Phill
źródło
Jestem z tobą, Phill, nie wiem, dlaczego ludzie głosują w dół, jeśli ktoś może, proszę ... proszę wyjaśnij, dlaczego?
PEO
18
Oddają głos, ponieważ pytanie dotyczy deserializacji bez typu.
richard
4
Odpowiedź była ważna w momencie pisania jej w 2010 r., Kiedy nie było innego rozwiązania. Była to nawet zaakceptowana odpowiedź na krótki czas, zanim wsparcie pojawiło się w JSON.NET.
Phill
1
To nie tworzy obiektu dynamicznego. To tworzy obiekt JObject, który określasz jako dynamiczny. Ale to wciąż JObject w środku.
ghostbust555
5

Jeśli używasz JSON.NET ze starą wersją, która nie JObject.

Jest to kolejny prosty sposób na utworzenie obiektu dynamicznego z JSON: https://github.com/chsword/jdynamic

NuGet Zainstaluj

PM> Install-Package JDynamic

Wsparcie przy użyciu indeksu ciągów, aby uzyskać dostęp do członka, takiego jak:

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

Przypadek testowy

Możesz użyć tego narzędzia w następujący sposób:

Uzyskaj wartość bezpośrednio

dynamic json = new JDynamic("1");

//json.Value

2. Pobierz element członkowski w obiekcie 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.Ilość

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.

Inny

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

//json.a.a is 1.
miecz
źródło
2

Tak to mozliwe. Robiłem to cały czas.

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

Jest to nieco trudniejsze w przypadku typów innych niż rodzime. Załóżmy, że w twoim Obj znajdują się obiekty ClassA i ClassB. Wszystkie są konwertowane na JObject. Co musisz zrobić, to:

ClassA ObjA = Obj.ObjA.ToObject<ClassA>();
ClassB ObjB = Obj.ObjB.ToObject<ClassB>();
sk
źródło