Есть ли способ десериализации содержимого JSON в динамический тип C # 4? Было бы неплохо пропустить создание группы классов, чтобы использовать DataContractJsonSerializer.
Если вы хотите что-то «динамическое», почему бы просто не использовать методы доступа в стиле get, которые поставляются с большинством JSON-декодеров, которые не идут в plain-old-object? (например, есть ли необходимость в создании «динамического» объекта?) В json.org есть несколько ссылок для реализаций C # JSON.
Я работаю над проектом, который пытается свести внешние зависимости к минимуму. Так что, если возможно что-то с серийными сериализаторами .net и типами, которые будут предпочтительнее. Конечно, если это невозможно, я подключаюсь к json.org. Спасибо!
Jswanson
42
Я действительно удивлен, что команда C # добавила «динамический», но в CLR нет способа преобразовать объект JSON в экземпляр динамического класса CLR.
Фрэнк Швитерман
2
К сожалению, принятый ответ не работает в .NET 4 RTM. Я опубликовал ответ, который помог мне разобраться с этим, что может быть полезно для других.
Дрю Ноакс
(Хотя, похоже, что Newtonsoft JSON.NET подходит довольно близко. Однако хороших примеров не существует.)
Hot Licks,
Ответы:
660
Если вы счастливы иметь зависимость от System.Web.Helpersсборки, тогда вы можете использовать Jsonкласс:
dynamic data =Json.Decode(json);
Он включен в инфраструктуру MVC в качестве дополнительной загрузки для платформы .NET 4. Не забудьте дать Владу голос, если это поможет! Однако, если вы не можете предположить, что клиентская среда включает эту DLL, продолжайте чтение.
Альтернативный десериализация подход предлагается здесь . Я немного изменил код, чтобы исправить ошибку и соответствовать моему стилю кодирования. Все, что вам нужно, это код и ссылка System.Web.Extensionsиз вашего проекта:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;publicsealedclassDynamicJsonConverter:JavaScriptConverter{publicoverrideobjectDeserialize(IDictionary<string,object> dictionary,Type type,JavaScriptSerializer serializer){if(dictionary ==null)thrownewArgumentNullException("dictionary");return type ==typeof(object)?newDynamicJsonObject(dictionary):null;}publicoverrideIDictionary<string,object>Serialize(object obj,JavaScriptSerializer serializer){thrownewNotImplementedException();}publicoverrideIEnumerable<Type>SupportedTypes{get{returnnewReadOnlyCollection<Type>(newList<Type>(new[]{typeof(object)}));}}#region Nested type: DynamicJsonObjectprivatesealedclassDynamicJsonObject:DynamicObject{privatereadonlyIDictionary<string,object> _dictionary;publicDynamicJsonObject(IDictionary<string,object> dictionary){if(dictionary ==null)thrownewArgumentNullException("dictionary");
_dictionary = dictionary;}publicoverridestringToString(){var sb =newStringBuilder("{");ToString(sb);return sb.ToString();}privatevoidToString(StringBuilder sb){var firstInDictionary =true;foreach(var pair in _dictionary){if(!firstInDictionary)
sb.Append(",");
firstInDictionary =false;varvalue= pair.Value;var name = pair.Key;if(valueisstring){
sb.AppendFormat("{0}:\"{1}\"", name,value);}elseif(valueisIDictionary<string,object>){newDynamicJsonObject((IDictionary<string,object>)value).ToString(sb);}elseif(valueisArrayList){
sb.Append(name +":[");var firstInArray =true;foreach(var arrayValue in(ArrayList)value){if(!firstInArray)
sb.Append(",");
firstInArray =false;if(arrayValue isIDictionary<string,object>)newDynamicJsonObject((IDictionary<string,object>)arrayValue).ToString(sb);elseif(arrayValue isstring)
sb.AppendFormat("\"{0}\"", arrayValue);else
sb.AppendFormat("{0}", arrayValue);}
sb.Append("]");}else{
sb.AppendFormat("{0}:{1}", name,value);}}
sb.Append("}");}publicoverrideboolTryGetMember(GetMemberBinder binder,outobject result){if(!_dictionary.TryGetValue(binder.Name,out result)){// return null to avoid exception. caller can check for null this way...
result =null;returntrue;}
result =WrapResultObject(result);returntrue;}publicoverrideboolTryGetIndex(GetIndexBinder binder,object[] indexes,outobject result){if(indexes.Length==1&& indexes[0]!=null){if(!_dictionary.TryGetValue(indexes[0].ToString(),out result)){// return null to avoid exception. caller can check for null this way...
result =null;returntrue;}
result =WrapResultObject(result);returntrue;}returnbase.TryGetIndex(binder, indexes,out result);}privatestaticobjectWrapResultObject(object result){var dictionary = result asIDictionary<string,object>;if(dictionary !=null)returnnewDynamicJsonObject(dictionary);var arrayList = result asArrayList;if(arrayList !=null&& arrayList.Count>0){return arrayList[0]isIDictionary<string,object>?newList<object>(arrayList.Cast<IDictionary<string,object>>().Select(x =>newDynamicJsonObject(x))):newList<object>(arrayList.Cast<object>());}return result;}}#endregion}
Я получаю ошибку в динамическом obj = serializer.Deserialize (json, typeof (object)); говоря, что нет перегрузки для метода с 2 аргументами .. неправильная DLL или что?
Стьюи Гриффин
32
Вы можете использовать System.Web.Helpers.Json - он предлагает метод Decode, который возвращает динамический объект. Я также разместил эту информацию в качестве ответа.
Влад Илиеску
2
Это также очень помогло мне, но мне любопытно, что мне делать, если мне нужно использовать метод .Serialize, который в настоящее время только генерирует исключение NotImplementedException ... Я не слишком знаком с запечатанными классами и / или расширенными абстрактными классы. Может кто-то указать мне верное направление?
Кори У.
2
иногда в js у вас есть поля со специальными символами, такими как "background-color". Для доступа к таким полям в js вы делаете obj ["background-color"]. Как я могу получить доступ к таким полям из C # после десериализации в динамический объект? Конечно, я не могу сделать obj.background-color, а obj ["background-color"], похоже, не работает. Было бы хорошо, если бы к динамическому объекту можно было также обращаться как к словарю, точно так же, как в js.
Раду Симионеску
2
@RaduSimionescu Я, наверное, немного опоздал, но, возможно, это поможет будущим посетителям. У меня была такая же проблема, только с именем поля params(это ключевое слово в C #). В дополнение к TryGetMemberвы можете переопределить TryGetIndex, что дает вам точно такое же поведение, как в JS. Тогда вы можете сделать obj["params"]или obj["background-color"]для неловких имен полей.
@HotLicks: Чтобы проанализировать динамику, stuffсделайте что-то вроде:foreach (Newtonsoft.Json.Linq.JProperty jproperty in stuff) { Console.WriteLine("jproperty.Name = {0}", jproperty.Name);}
Matthias
11
В чем разница между JsonConvert.DeserializeObject и JObject.Parse? Ответ использует их обоих одинаково, чтобы сделать одно и то же, но не объясняет разницу.
cja
7
@TomPeplow Пробовал это. Это не сработало для меня. Он говорит, что «JObject не реализует« Имя »».
Я не могу заставить это работать. Я сузил вопрос до того, чтобы быть внутри asyncметода. Если я сделаю метод синхронным, он будет работать как положено. Однако, сделайте метод, asyncи я не могу получить dynamic, я просто получаю object. Явное приведение ничего не делает, все еще только дает мне object. Кто-нибудь еще переживает это?
codeConcussion
295
Вы можете сделать это, используя System.Web.Helpers.Json - его метод Decode возвращает динамический объект, который вы можете перемещать по своему усмотрению.
Он включен в сборку System.Web.Helpers (.NET 4.0).
ты пробовал это? Это возвращается Dictionary<string,object>. Если я что-то упустил, ваш пример не возвращает динамический объект.
sergiopereira
18
Это не работает, это просто возвращает dict в форме динамического
mattmanser
55
@ Питер Лонг, я полагаю, что не смог четко изложить свое дело, дорогой парень. Позвольте мне попытаться исправить мою ошибку. Я знаю, что такое динамика. Это не позволяет вам передавать объект JSON и использовать d.code, вам нужно будет выполнить d ["code"]. Значение, а не то, чего хочет большинство людей, находящих этот ответ, мы уже знаем, как получить словарь и привести его к динамике - это пустая трата времени. Я с уважением не согласен, сэр.
Mattmanser
4
@mattmanser we already know how to get the dictionary and casting it to a dynamic. Это не должно быть dictionay. Json также имеет списки помимо словаря. А также списки и словари могут быть вложенными. Мой код может обрабатывать все эти ситуации. НО ваш метод не может.
Питер Лонг
4
@mattmanser прав; возможно реализовать IDynamicMetaObjectProvider(или использовать, например ExpandoObject), который может перехватывать свойства и искать их во внутреннем словаре. Это в сочетании с использованием dynamicпозволяет использовать такой код d.code. Отчасти бессмысленно приводить словарь в динамику.
Стивен Дрю
78
Простые «строковые данные JSON» для объекта без стороннего DLL-файла:
WebClient client =newWebClient();string getString = client.DownloadString("https://graph.facebook.com/zuck");JavaScriptSerializer serializer =newJavaScriptSerializer();dynamic item = serializer.Deserialize<object>(getString);string name = item["name"];//note: JavaScriptSerializer in this namespaces//System.Web.Script.Serialization.JavaScriptSerializer
Примечание: вы также можете использовать свой пользовательский объект.
Я бы не понял. Это, безусловно, самое простое решение, и никто не упоминает об этом.
cikatomo
2
да, это просто :) иногда вам нужно сериализовать, но не хотите включать третью часть dll
İbrahim Özbölük
Вы можете уточнить: как динамический доступ десериализованного объект через: myObject["myprop"]? Я знаю, что это делается во время выполнения, но как myObject["myprop"]действителен доступ к нему через ?
Рой Намир
1
Вы можете десериализовать ваш объект как Personel item = serializer.Deserialize <Personel> (getString); и если вы используете динамический объект, вы также можете использовать массив, и все возможно, как любой объект
İbrahim Özbölük
3
Для использования пространства имен System.Web.Script.Serialization вашему проекту требуется ссылка на System.Web.Extensions.
StilgarISCA
28
JsonFx может десериализовать контент JSON в динамические объекты.
Сериализация в / из динамических типов (по умолчанию для .NET 4.0):
Я сделал новую версию DynamicJsonConverter, которая использует Expando Objects. Я использовал объекты раскрытия, потому что я хотел сериализовать динамический обратно в JSON, используя Json.NET.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Web.Script.Serialization;publicstaticclassDynamicJson{publicstaticdynamicParse(string json){JavaScriptSerializer jss =newJavaScriptSerializer();
jss.RegisterConverters(newJavaScriptConverter[]{newDynamicJsonConverter()});dynamic glossaryEntry = jss.Deserialize(json,typeof(object))asdynamic;return glossaryEntry;}classDynamicJsonConverter:JavaScriptConverter{publicoverrideobjectDeserialize(IDictionary<string,object> dictionary,Type type,JavaScriptSerializer serializer){if(dictionary ==null)thrownewArgumentNullException("dictionary");var result =ToExpando(dictionary);return type ==typeof(object)? result :null;}privatestaticExpandoObjectToExpando(IDictionary<string,object> dictionary){var result =newExpandoObject();var dic = result asIDictionary<String,object>;foreach(var item in dictionary){var valueAsDic = item.ValueasIDictionary<string,object>;if(valueAsDic !=null){
dic.Add(item.Key,ToExpando(valueAsDic));continue;}var arrayList = item.ValueasArrayList;if(arrayList !=null&& arrayList.Count>0){
dic.Add(item.Key,ToExpando(arrayList));continue;}
dic.Add(item.Key, item.Value);}return result;}privatestaticArrayListToExpando(ArrayList obj){ArrayList result =newArrayList();foreach(var item in obj){var valueAsDic = item asIDictionary<string,object>;if(valueAsDic !=null){
result.Add(ToExpando(valueAsDic));continue;}var arrayList = item asArrayList;if(arrayList !=null&& arrayList.Count>0){
result.Add(ToExpando(arrayList));continue;}
result.Add(item);}return result;}publicoverrideIDictionary<string,object>Serialize(object obj,JavaScriptSerializer serializer){thrownewNotImplementedException();}publicoverrideIEnumerable<Type>SupportedTypes{get{returnnewReadOnlyCollection<Type>(newList<Type>(new[]{typeof(object)}));}}}}
dynamic json =newJDynamic("{a:'abc'}");// json.a is a string "abc"dynamic json =newJDynamic("{a:3.1416}");// json.a is 3.1416mdynamic json =newJDynamic("{a:1}");// json.a isdynamic json =newJDynamic("[1,2,3]");/json.Length/json.Countis3// And you can use json[0]/ json[2] to get the elementsdynamic json =newJDynamic("{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 elementsdynamic json =newJDynamic("[{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.
Вы можете расширить JavaScriptSerializer, чтобы рекурсивно скопировать созданный им словарь для расширения объектов и затем использовать их динамически:
Тогда вам просто нужно иметь оператор using для пространства имен, в котором вы определили расширение (рассмотрите возможность их определения в System.Web.Script.Serialization ... другой прием - не использовать пространство имен, тогда вам не нужно использовать заявление на всех) и вы можете потреблять их так:
var serializer =newJavaScriptSerializer();varvalue= serializer.DeserializeDynamic("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");var name =(string)value.Name;// Jon Smithvar age =(int)value.Age;// 42var address =value.Address;var city =(string)address.City;// New Yorkvar state =(string)address.State;// NY
publicclassChild{publicstring name {get;set;}publicint age {get;set;}}publicclassPerson{publicstring name {get;set;}publicint age {get;set;}publicstring city {get;set;}publicList<Child>Childs{get;set;}}
После этого я использую Newtonsoft.Json для заполнения класса:
using Newtonsoft.Json;
namespace GitRepositoryCreator.Common{classJObjects{publicstaticstringGet(object p_object){returnJsonConvert.SerializeObject(p_object);}internalstatic T Get<T>(string p_object){returnJsonConvert.DeserializeObject<T>(p_object);}}}
Вы можете назвать это так:
Person jsonClass =JObjects.Get<Person>(stringJson);string stringJson =JObjects.Get(jsonClass);
PS:
Если ваше имя переменной JSON не является допустимым именем C # (имя начинается с $), вы можете исправить это следующим образом:
Для этого я использовал бы JSON.NET, чтобы выполнить низкоуровневый анализ потока JSON, а затем создать иерархию объектов из экземпляров ExpandoObjectкласса.
Теперь мы десериализовали строку БЕЗ ссылки на вышеупомянутые классы:
var dyn =JsonConvert.DeserializeObject<JObject>(jsonAsFooString);JProperty propAge = dyn.Properties().FirstOrDefault(i=>i.Name=="Age");if(propAge !=null){int age =int.Parse(propAge.Value.ToString());Console.WriteLine("age="+ age);}//or as a one-liner:int myage =int.Parse(dyn.Properties().First(i=>i.Name=="Age").Value.ToString());
Или, если вы хотите пойти глубже:
var propBar = dyn.Properties().FirstOrDefault(i=>i.Name=="Bar");if(propBar !=null){JObject o =(JObject)propBar.First();var propBDay = o.Properties().FirstOrDefault(i => i.Name=="BDay");if(propBDay !=null){DateTime bday =DateTime.Parse(propBDay.Value.ToString());Console.WriteLine("birthday="+ bday.ToString("MM/dd/yyyy"));}}//or as a one-liner:DateTime mybday =DateTime.Parse(((JObject)dyn.Properties().First(i=>i.Name=="Bar").First()).Properties().First(i=>i.Name=="BDay").Value.ToString());
Этот подход позволяет «обойти» документ jSON, чтобы вы могли управлять ситуацией, когда структура JSON неизвестна или является переменной (например, многие API возвращают совершенно другой документ JSON при возникновении ошибки). Есть другие библиотеки, которые позволяют это делать, кроме Newtonsoft.JSON (также известный как JSON.NET)?
Алекс 75
4
Требуемый объект DynamicJSONObject включен в System.Web.Helpers.dll из пакета веб-страниц ASP.NET, который является частью WebMatrix.
Используйте DataSet (C #) с JavaScript. Простая функция для создания потока JSON с вводом DataSet. Создайте содержимое в формате JSON, как (набор данных из нескольких таблиц):
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;Container container =JsonConvert.Deserialize<Container>(jsonAsString,newExpandoObjectConverter());
var jsonString =(File.ReadAllText(Path.Combine(Directory.GetCurrentDirectory(),"delete_result.json")));var objects =JsonConvert.DeserializeObject<dynamic>(jsonString);foreach(var o in objects){Console.WriteLine($"{o.id.ToString()}");}
Ответы:
Если вы счастливы иметь зависимость от
System.Web.Helpers
сборки, тогда вы можете использоватьJson
класс:Он включен в инфраструктуру MVC в качестве дополнительной загрузки для платформы .NET 4. Не забудьте дать Владу голос, если это поможет! Однако, если вы не можете предположить, что клиентская среда включает эту DLL, продолжайте чтение.
Альтернативный десериализация подход предлагается здесь . Я немного изменил код, чтобы исправить ошибку и соответствовать моему стилю кодирования. Все, что вам нужно, это код и ссылка
System.Web.Extensions
из вашего проекта:Вы можете использовать это так:
Итак, учитывая строку JSON:
Следующий код будет работать во время выполнения:
источник
params
(это ключевое слово в C #). В дополнение кTryGetMember
вы можете переопределитьTryGetIndex
, что дает вам точно такое же поведение, как в JS. Тогда вы можете сделатьobj["params"]
илиobj["background-color"]
для неловких имен полей.Это довольно просто с помощью Json.NET :
Также
using Newtonsoft.Json.Linq
:Документация: запрос JSON с динамическим
источник
stuff
сделайте что-то вроде:foreach (Newtonsoft.Json.Linq.JProperty jproperty in stuff) { Console.WriteLine("jproperty.Name = {0}", jproperty.Name);}
async
метода. Если я сделаю метод синхронным, он будет работать как положено. Однако, сделайте метод,async
и я не могу получитьdynamic
, я просто получаюobject
. Явное приведение ничего не делает, все еще только дает мнеobject
. Кто-нибудь еще переживает это?Вы можете сделать это, используя System.Web.Helpers.Json - его метод Decode возвращает динамический объект, который вы можете перемещать по своему усмотрению.
Он включен в сборку System.Web.Helpers (.NET 4.0).
источник
.NET 4.0 имеет встроенную библиотеку для этого:
Это самый простой способ.
источник
Dictionary<string,object>
. Если я что-то упустил, ваш пример не возвращает динамический объект.we already know how to get the dictionary and casting it to a dynamic
. Это не должно быть dictionay. Json также имеет списки помимо словаря. А также списки и словари могут быть вложенными. Мой код может обрабатывать все эти ситуации. НО ваш метод не может.IDynamicMetaObjectProvider
(или использовать, напримерExpandoObject
), который может перехватывать свойства и искать их во внутреннем словаре. Это в сочетании с использованиемdynamic
позволяет использовать такой кодd.code
. Отчасти бессмысленно приводить словарь в динамику.Простые «строковые данные JSON» для объекта без стороннего DLL-файла:
Примечание: вы также можете использовать свой пользовательский объект.
источник
myObject["myprop"]
? Я знаю, что это делается во время выполнения, но какmyObject["myprop"]
действителен доступ к нему через ?JsonFx может десериализовать контент JSON в динамические объекты.
источник
Я сделал новую версию DynamicJsonConverter, которая использует Expando Objects. Я использовал объекты раскрытия, потому что я хотел сериализовать динамический обратно в JSON, используя Json.NET.
источник
Еще один способ использования Newtonsoft.Json :
источник
Вы можете достичь этого с помощью Newtonsoft.Json. Установите Newtonsoft.Json из Nuget и выполните следующие действия:
источник
Самый простой способ:
Просто включите этот файл DLL .
Используйте код как это:
источник
Вы можете расширить JavaScriptSerializer, чтобы рекурсивно скопировать созданный им словарь для расширения объектов и затем использовать их динамически:
Тогда вам просто нужно иметь оператор using для пространства имен, в котором вы определили расширение (рассмотрите возможность их определения в System.Web.Script.Serialization ... другой прием - не использовать пространство имен, тогда вам не нужно использовать заявление на всех) и вы можете потреблять их так:
источник
Ты можешь использовать
using Newtonsoft.Json
resolvedEvent.Event.Data
мой ответ от вызова основного события.источник
Я использую http://json2csharp.com/, чтобы получить класс, представляющий объект JSON.
Входные данные:
Вывод:
После этого я использую Newtonsoft.Json для заполнения класса:
Вы можете назвать это так:
PS:
Если ваше имя переменной JSON не является допустимым именем C # (имя начинается с
$
), вы можете исправить это следующим образом:источник
Для этого я использовал бы JSON.NET, чтобы выполнить низкоуровневый анализ потока JSON, а затем создать иерархию объектов из экземпляров
ExpandoObject
класса.источник
Я использую как это в моем коде, и он работает нормально
источник
Посмотрите на статью, которую я написал на CodeProject, которая точно отвечает на вопрос:
Динамические типы с JSON.NET
Здесь слишком много места для повторной публикации, и еще меньше смысла, поскольку в этой статье есть вложение с ключом / необходимым исходным файлом.
источник
Другой вариант - «Вставить JSON как классы», чтобы его можно было быстро и легко десериализовать.
Вот лучшее объяснение n piccas ... «Вставить JSON As Classes» в ASP.NET и Web Tools 2012.2 RC
источник
Десериализация в JSON.NET может быть динамической, используя
JObject
класс, который включен в эту библиотеку. Моя строка JSON представляет эти классы:Теперь мы десериализовали строку БЕЗ ссылки на вышеупомянутые классы:
Или, если вы хотите пойти глубже:
Смотрите пост для полного примера.
источник
Требуемый объект DynamicJSONObject включен в System.Web.Helpers.dll из пакета веб-страниц ASP.NET, который является частью WebMatrix.
источник
Существует легкая библиотека JSON для C #, которая называется SimpleJson .
Он поддерживает .NET 3.5+, Silverlight и Windows Phone 7.
Он поддерживает динамический для .NET 4.0
Он также может быть установлен как пакет NuGet
источник
Используйте DataSet (C #) с JavaScript. Простая функция для создания потока JSON с вводом DataSet. Создайте содержимое в формате JSON, как (набор данных из нескольких таблиц):
Просто на стороне клиента, используйте eval. Например,
Тогда используйте:
источник
Чтобы получить ExpandoObject:
источник
Попробуй это:
источник
Как анализировать легкий JSON-контент с помощью динамического и JavaScriptSerializer
Пожалуйста, добавьте ссылку на System.Web.Extensions и добавьте это пространство имен
using System.Web.Script.Serialization;
вверху:Как проанализировать вложенный и сложный JSON с помощью динамического и JavaScriptSerializer
Пожалуйста, добавьте ссылку на System.Web.Extensions и добавьте это пространство имен
using System.Web.Script.Serialization;
вверху:источник
С Cinchoo ETL - библиотека с открытым исходным кодом, доступная для анализа JSON в динамический объект:
Вывод:
Отказ от ответственности: я автор этой библиотеки.
источник
попробуй так!
Пример JSON:
Код C #:
источник