Десериализовать объект json в динамический объект с помощью Json.net

426

Можно ли вернуть динамический объект из десериализации json, используя json.net? Я хотел бы сделать что-то вроде этого:

dynamic jsonResponse = JsonConvert.Deserialize(json);
Console.WriteLine(jsonResponse.message);
ryudice
источник
1
Подумайте о том, чтобы сгенерировать класс C # из JSON json2csharp.com и использовать сгенерированный класс вместо динамического
Майкл Фрейдгейм
Как вы предлагаете stackOverflow закрыть вопрос как "слишком старый"? Прошло шесть лет, с тех пор есть правильные ответы и разумные предложения для каждой версии .net ... так много, что они больше не помогают.
Эндрю Лориен

Ответы:

547

Json.NET позволяет нам сделать это:

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

Вывод:

 1000
 string
 6

Документация здесь: LINQ to JSON с Json.NET

Смотрите также JObject.Parse и JArray.Parse

Михаил Паханцов
источник
36
Обратите внимание, что для массивов синтаксис JArray.Parse.
jgillich
4
Почему нам нужно использовать динамическое слово? я боюсь никогда не использовать раньше: D
MonsterMMORPG
3
В VB.Net нужно это сделатьDim d As Object = JObject.Parse("{number:1000, str:'string', array: [1,2,3,4,5,6]}")
ilans
2
@MonsterMMORPG Вы должны быть :) Dynamic - это анти-паттерн почти во всех обстоятельствах, но время от времени у вас может возникнуть ситуация, когда его целесообразно использовать.
Pluc
4
В случае Newtonsoft.Json 8.0.3 (.NET 4.5.2): возникло исключение Microsoft.CSharp.RuntimeBinder.RuntimeBinderException HResult = -2146233088 Сообщение = 'Newtonsoft.Json.Linq.JObject' не содержит определения для 'number' Source = Microsoft .CSharp StackTrace: в Microsoft.CSharp.RuntimeBinder.RuntimeBinderController.SubmitError (CError pError)
user4698855
107

Начиная с Json.NET 4.0 Release 1 имеется встроенная динамическая поддержка:

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

И, конечно же, лучший способ получить текущую версию - через NuGet.

Обновлено (12/12/2014) для учета комментариев:

Это прекрасно работает. Если вы проверите тип в отладчике, вы увидите, что значение, по сути, является динамическим . Базового типа является JObject. Если вы хотите контролировать тип (например, указать ExpandoObject, то сделайте это).

введите описание изображения здесь

Дэвид Педен
источник
20
Кажется, это никогда не работает. Он возвращает только JObject, а не динамическую переменную.
Пол
12
Кстати, это работает: JsonConvert.DeserializeObject <ExpandoObject> (STRING); с правильной десериализацией, поэтому у нас нет JObject и т. д.
Gutek
2
@ Гутек не уверен, в чем твоя проблема. Вы запускали код? Я добавил утверждения в тест и добавил свойство, отсутствующее в исходном json. Скриншот отладчика включен.
Дэвид Педен
1
@DavidPeden, если у вас есть JObject и вы попытаетесь связать это, в Razor вы получите исключения. Вопрос был о десериализации динамического объекта - JObject является динамическим, но содержит «собственные» типы, такие как JValue, а не примитивные типы. Я не могу использовать @Model.Propимя в Razor, если тип возвращаемого значения - JValue.
Гутек
2
Это работает, но каждое динамическое свойство является JValue. Что смутило меня, потому что я работал в окне отладчика / непосредственного окна и не видел только strings. Дэвид показывает это на нижнем скриншоте. Это JValueконвертируемый, так что вы можете просто сделатьstring m = jsonResponse.message
Люк Пуплетт
66

Если вы просто десериализуетесь в динамический, вы получите JObject обратно. Вы можете получить то, что вы хотите, используя ExpandoObject.

var converter = new ExpandoObjectConverter();    
dynamic message = JsonConvert.DeserializeObject<ExpandoObject>(jsonString, converter);
Джошуа Петерсон
источник
1
Результат может быть также преобразован в словарь
FindOutIslamNow
1
Именно то, что я искал! Спасибо!
DarkDeny
42

Я знаю, что это старый пост, но JsonConvert на самом деле имеет другой метод, поэтому было бы

var product = new { Name = "", Price = 0 };
var jsonResponse = JsonConvert.DeserializeAnonymousType(json, product);
epitka
источник
23
Это было бы десериализацией полезной нагрузки json в анонимный тип, а не динамический тип. Анонимные типы и динамические типы - это разные вещи, и я не верю, что это отвечает на заданный вопрос.
jrista
1
Нужно ли использовать две переменные? Почему бы не использовать первый во втором утверждении?
RenniePet
21

Да, вы можете сделать это с помощью JsonConvert.DeserializeObject. Для этого достаточно просто сделать:

dynamic jsonResponse = JsonConvert.DeserializeObject(json);
Console.WriteLine(jsonResponse["message"]);
oteal
источник
1
JsonConvertне содержит вызванный метод Deserialize.
Может Пойразоглу
это должен быть только DeserializeObject, но это должен быть принятый ответ IMO
superjugy
21

Примечание. В то время, когда я отвечал на этот вопрос в 2010 году, не было никакого способа десериализации без какого-либо типа, это позволило вам десериализовать, не определяя фактический класс, и разрешило использовать анонимный класс для десериализации.


Вы должны иметь какой-то тип для десериализации. Вы могли бы сделать что-то вроде:

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

Мой ответ основан на решении для сборки .NET 4.0 в сериализаторе JSON. Ссылка для десериализации на анонимные типы находится здесь:

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

Phill
источник
Я с тобой, Фил, не знаю, почему люди голосуют против этого, если кто-нибудь может, пожалуйста, объясните, почему?
PEO
18
Они понижают голос, потому что речь идет о десериализации без типа.
Ричард
4
Ответ был действителен на момент написания его в 2010 году, когда не было другого решения. Это был даже принятый ответ в течение небольшого периода времени, пока не появилась поддержка в JSON.NET.
Фил
1
Это не производит динамический объект. Это создает JObject, который вы называете динамическим. Но это все еще JObject внутри.
ghostbust555
5

Если вы используете JSON.NET со старой версией, которая не JObject.

Это еще один простой способ сделать динамический объект из JSON: https://github.com/chsword/jdynamic

NuGet Установить

PM> Install-Package JDynamic

Поддержка использования строкового индекса для доступа к члену, как:

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

Прецедент

И вы можете использовать эту утилиту следующим образом:

Получить значение напрямую

dynamic json = new JDynamic("1");

//json.Value

2. Получить член в объекте 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.

Другой

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

//json.a.a is 1.
chsword
источник
2

Да, это возможно. Я делал это все время.

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

Это немного сложнее для неродного типа. Предположим, внутри вашего объекта Obj есть объекты ClassA и ClassB. Все они конвертированы в JObject. Что вам нужно сделать, это:

ClassA ObjA = Obj.ObjA.ToObject<ClassA>();
ClassB ObjB = Obj.ObjB.ToObject<ClassB>();
ск
источник