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


426

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

dynamic jsonResponse = JsonConvert.Deserialize(json);
Console.WriteLine(jsonResponse.message);

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

23
Это было бы десериализацией полезной нагрузки json в анонимный тип, а не динамический тип. Анонимные типы и динамические типы - это разные вещи, и я не верю, что это отвечает на заданный вопрос.
jrista

1
Нужно ли использовать две переменные? Почему бы не использовать первый во втором утверждении?
RenniePet

21

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

dynamic jsonResponse = JsonConvert.DeserializeObject(json);
Console.WriteLine(jsonResponse["message"]);

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


Я с тобой, Фил, не знаю, почему люди голосуют против этого, если кто-нибудь может, пожалуйста, объясните, почему?
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.

2

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

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

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

ClassA ObjA = Obj.ObjA.ToObject<ClassA>();
ClassB ObjB = Obj.ObjB.ToObject<ClassB>();
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.