Десеріалізація об'єкта json в динамічний об'єкт за допомогою Json.net


426

Чи можливо повернути динамічний об’єкт з деріаріалізації json за допомогою json.net? Я хотів би зробити щось подібне:

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

1
Подумайте про створення класу C # з JSON json2csharp.com та використання генерованого класу замість динамічного
Michael Freidgeim


Як ви пропонуєте stackOverflow закрити питання як "занадто старе"? Пройшло шість років, з тих пір є вагомі відповіді та обґрунтовані пропозиції для кожної версії .net ... стільки, що вони вже не дуже корисні.
andrew lorien

Відповіді:


546

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 до 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 Вам слід бути :) Динамічний - це анти-шаблон майже в будь-яких обставинах, але час від часу у вас може виникнути ситуація, коли його розумно використовувати.
Плук

4
З Newtonsoft.Json 8.0.3 (.NET 4.5.2): Microsoft.CSharp.RuntimeBinder.RuntimeBinderException сталося HResult = -2146233088 Повідомлення = 'Newtonsoft.Json.Linq.JObject' не містить визначення для 'число' Source = Microsoft .CSharp StackTrace: в Microsoft.CSharp.RuntimeBinder.RuntimeBinderController.SubmitError (CError pError)
користувач4698855

107

Станом на Json.NET 4.0, випуск 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
BTW, це працює: JsonConvert.DeserializeObject <ExpandoObject> (STRING); при правильній десеріалізації, тому у нас немає JObject тощо.
Гутек

2
@Gutek не впевнений, у чому полягає ваша проблема. Ви запустили код? Я додав твердження до тесту і додав властивість не в оригінальному json. Знімок екрана відладчика включений.
Девід Педен

1
@DavidPeden, якщо у вас є JObject, і ви спробуєте прив'язати, що в Razor ви отримаєте винятки. Питання стосувалося десеріалізації до динамічного об'єкта - JObject є динамічним, але містить "власні" типи, такі як JValue, а не примітивні типи. Я не можу використовувати @Model.Propім'я в Razor, якщо тип повернення - JValue.
Гутек

2
Це працює, але кожна динамічна властивість є a JValue. Що мене бентежило, бо я працював у відладці / безпосередньому вікні і не бачив просто strings. Девід показує це на нижньому екрані екрана. JValueКонвертується , так що ви можете просто зробитиstring m = jsonResponse.message
Luke Puplett

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.
Може Poyrazoğlu

це має бути просто DeserializeObject, але це має бути прийнята відповідь ІМО
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


Я з вами не знаю, навіщо це люди, які голосують таким чином, якщо хтось може, будь ласка, поясніть, чому?
ПЕО

18
Вони підкреслюють те, що питання стосується десеріалізації без типу.
Річард

4
Відповідь була дійсною на момент написання її в 2010 році, коли іншого рішення не було. Це була навіть прийнята відповідь протягом невеликого періоду часу, поки підтримка не надійшла в JSON.NET.
Філ

1
Це не створює динамічного об'єкта. Це створює JObject, який ви називаєте динамічним. Але все ще є JObject всередині.
ghostbust555

5

Якщо ви використовуєте JSON.NET зі старою версією, яка не JObject.

Це ще один простий спосіб зробити динамічний об’єкт з JSON: https://github.com/chsword/jdynamic

NuGet Install

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.Незліченна

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.