Десериализовать JSON в C # динамический объект?

842

Есть ли способ десериализации содержимого JSON в динамический тип С# 4? Было бы неплохо пропустить создание группы классов, чтобы использовать DataContractJsonSerializer.

  • 5
    Если вы хотите что-то «динамическое», почему бы просто не использовать методы доступа в стиле get, которые поставляются с большинством JSON-декодеров, которые не идут в plain-old-object? (например, есть ли необходимость в создании «динамического» объекта?) json.org содержит множество ссылок для реализаций C # JSON.
  • 0
    Я работаю над проектом, который пытается свести внешние зависимости к минимуму. Так что, если возможно что-то с серийными сериализаторами .net и типами, которые будут предпочтительнее. Конечно, если это невозможно, я подключаюсь к json.org. Спасибо!
Показать ещё 4 комментария
Теги:
dynamic
serialization

25 ответов

581
Лучший ответ

Если вы счастливы иметь зависимость от сборки 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;

public sealed class DynamicJsonConverter : JavaScriptConverter
{
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");

        return type == typeof(object) ? new DynamicJsonObject(dictionary) : null;
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override IEnumerable<Type> SupportedTypes
    {
        get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(object) })); }
    }

    #region Nested type: DynamicJsonObject

    private sealed class DynamicJsonObject : DynamicObject
    {
        private readonly IDictionary<string, object> _dictionary;

        public DynamicJsonObject(IDictionary<string, object> dictionary)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");
            _dictionary = dictionary;
        }

        public override string ToString()
        {
            var sb = new StringBuilder("{");
            ToString(sb);
            return sb.ToString();
        }

        private void ToString(StringBuilder sb)
        {
            var firstInDictionary = true;
            foreach (var pair in _dictionary)
            {
                if (!firstInDictionary)
                    sb.Append(",");
                firstInDictionary = false;
                var value = pair.Value;
                var name = pair.Key;
                if (value is string)
                {
                    sb.AppendFormat("{0}:\"{1}\"", name, value);
                }
                else if (value is IDictionary<string, object>)
                {
                    new DynamicJsonObject((IDictionary<string, object>)value).ToString(sb);
                }
                else if (value is ArrayList)
                {
                    sb.Append(name + ":[");
                    var firstInArray = true;
                    foreach (var arrayValue in (ArrayList)value)
                    {
                        if (!firstInArray)
                            sb.Append(",");
                        firstInArray = false;
                        if (arrayValue is IDictionary<string, object>)
                            new DynamicJsonObject((IDictionary<string, object>)arrayValue).ToString(sb);
                        else if (arrayValue is string)
                            sb.AppendFormat("\"{0}\"", arrayValue);
                        else
                            sb.AppendFormat("{0}", arrayValue);

                    }
                    sb.Append("]");
                }
                else
                {
                    sb.AppendFormat("{0}:{1}", name, value);
                }
            }
            sb.Append("}");
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            if (!_dictionary.TryGetValue(binder.Name, out result))
            {
                // return null to avoid exception.  caller can check for null this way...
                result = null;
                return true;
            }

            result = WrapResultObject(result);
            return true;
        }

        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object 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;
                    return true;
                }

                result = WrapResultObject(result);
                return true;
            }

            return base.TryGetIndex(binder, indexes, out result);
        }

        private static object WrapResultObject(object result)
        {
            var dictionary = result as IDictionary<string, object>;
            if (dictionary != null)
                return new DynamicJsonObject(dictionary);

            var arrayList = result as ArrayList;
            if (arrayList != null && arrayList.Count > 0)
            {
                return arrayList[0] is IDictionary<string, object> 
                    ? new List<object>(arrayList.Cast<IDictionary<string, object>>().Select(x => new DynamicJsonObject(x))) 
                    : new List<object>(arrayList.Cast<object>());
            }

            return result;
        }
    }

    #endregion
}

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

string json = ...;

var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new DynamicJsonConverter() });

dynamic obj = serializer.Deserialize(json, typeof(object));

Итак, учитывая строку JSON:

{
  "Items":[
    { "Name":"Apple", "Price":12.3 },
    { "Name":"Grape", "Price":3.21 }
  ],
  "Date":"21/11/2010"
}

Следующий код будет работать во время выполнения:

dynamic data = serializer.Deserialize(json, typeof(object));

data.Date; // "21/11/2010"
data.Items.Count; // 2
data.Items[0].Name; // "Apple"
data.Items[0].Price; // 12.3 (as a decimal)
data.Items[1].Name; // "Grape"
data.Items[1].Price; // 3.21 (as a decimal)
  • 0
    Спасибо, Дрю, ваш TryGetMember разобрал мою проблему вокруг повторного использования во вложенные коллекции, но не могли бы вы сообщить нам, что именно заставляет это работать. Дело в том, что списки массивов преобразуются в IDictionary, а затем проецируются как DynamicJsonObjects, а не проецируются как члены arrayList? Надеюсь, это не слишком глупый вопрос. Спасибо за ответ :)
  • 0
    @ Марк, давно я не смотрел на это, но по памяти то, что ты описываешь, звучит правильно.
Показать ещё 26 комментариев
481

Это довольно просто, используя Json.NET:

dynamic stuff = JsonConvert.DeserializeObject("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");

string name = stuff.Name;
string address = stuff.Address.City;

Также using Newtonsoft.Json.Linq:

dynamic stuff = JObject.Parse("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");

string name = stuff.Name;
string address = stuff.Address.City;

Документация: Запрос JSON с динамическим

  • 1
    Интересно, используя MVC, как мне связать это с представлением? Я прочитал несколько постов о динамическом или анонимном связывании типов, но не вижу примера, как его использовать. Скажем, у меня есть JSON, который может иметь много слоев.
  • 0
    Как вы можете анализировать динамические stuff ?
Показать ещё 10 комментариев
298

Вы можете сделать это с помощью System.Web.Helpers.Json - его метод Decode возвращает динамический объект, который вы можете перемещать по своему усмотрению.

Он включен в сборку System.Web.Helpers(.NET 4.0).

var dynamicObject = Json.Decode(jsonString);
  • 25
    FYI System.Web.Helpers.dll требует .net 4.0, но не входит в .net 4.0. Может быть установлен с ASP.NET MVC 3
  • 7
    Эта сборка находится в группе «Расширения» в разделе «Сборки в Visual Studio 2012».
Показать ещё 3 комментария
73

.Net 4.0 имеет встроенную библиотеку для этого:

using System.Web.Script.Serialization;
JavaScriptSerializer jss = new JavaScriptSerializer();
var d=jss.Deserialize<dynamic>(str);

Это самый простой способ.

  • 0
    Большинство предыдущих ответов было до .NET 4.0 RTM.
  • 27
    ты пробовал это? Возвращает Dictionary<string,object> . Если я что-то упустил, ваш пример не возвращает динамический объект.
Показать ещё 15 комментариев
70

Простые "строковые данные json" для объекта без какой-либо сторонней DLL

WebClient client = new WebClient();
string getString = client.DownloadString("https://graph.facebook.com/zuck");


JavaScriptSerializer serializer = new JavaScriptSerializer(); 
dynamic item = serializer.Deserialize<object>(getString);
string name = item["name"];

//note: JavaScriptSerializer in this namespaces
//System.Web.Script.Serialization.JavaScriptSerializer 

Примечание. Вы также можете использовать свой пользовательский объект.

Personel item = serializer.Deserialize<Personel>(getString);
  • 4
    Я бы не понял. Это, безусловно, самое простое решение, и никто не упоминает об этом.
  • 2
    да это просто :) иногда вам нужно сериализовать, но не хотите включать третью часть DLL
Показать ещё 3 комментария
27

JsonFx может десериализовать json в динамических объектах.

https://github.com/jsonfx/jsonfx

Сериализация в/из динамических типов (по умолчанию для.NET 4.0):

var reader = new JsonReader(); var writer = new JsonWriter();

string input = @"{ ""foo"": true, ""array"": [ 42, false, ""Hello!"", null ] }";
dynamic output = reader.Read(input);
Console.WriteLine(output.array[0]); // 42
string json = writer.Write(output);
Console.WriteLine(json); // {"foo":true,"array":[42,false,"Hello!",null]}
17

Я сделал новую версию DynamicJsonConverter, которая использует объекты Expando. Я использовал объекты expando, потому что я хотел Сериализовать динамику обратно в json с помощью Json.net.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Web.Script.Serialization;

public static class DynamicJson
{
    public static dynamic Parse(string json)
    {
        JavaScriptSerializer jss = new JavaScriptSerializer();
        jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() });

        dynamic glossaryEntry = jss.Deserialize(json, typeof(object)) as dynamic;
        return glossaryEntry;
    }

    class DynamicJsonConverter : JavaScriptConverter
    {
        public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");

            var result = ToExpando(dictionary);

            return type == typeof(object) ? result : null;
        }

        private static ExpandoObject ToExpando(IDictionary<string, object> dictionary)
        {
            var result = new ExpandoObject();
            var dic = result as IDictionary<String, object>;

            foreach (var item in dictionary)
            {
                var valueAsDic = item.Value as IDictionary<string, object>;
                if (valueAsDic != null)
                {
                    dic.Add(item.Key, ToExpando(valueAsDic));
                    continue;
                }
                var arrayList = item.Value as ArrayList;
                if (arrayList != null && arrayList.Count > 0)
                {
                    dic.Add(item.Key, ToExpando(arrayList));
                    continue;
                }

                dic.Add(item.Key, item.Value);
            }
            return result;
        }

        private static ArrayList ToExpando(ArrayList obj)
        {
            ArrayList result = new ArrayList();

            foreach (var item in obj)
            {
                var valueAsDic = item as IDictionary<string, object>;
                if (valueAsDic != null)
                {
                    result.Add(ToExpando(valueAsDic));
                    continue;
                }

                var arrayList = item as ArrayList;
                if (arrayList != null && arrayList.Count > 0)
                {
                    result.Add(ToExpando(arrayList));
                    continue;
                }

                result.Add(item);
            }
            return result;
        }

        public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
        {
            throw new NotImplementedException();
        }

        public override IEnumerable<Type> SupportedTypes
        {
            get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(object) })); }
        }
    }
}  
14

Другой способ: Newtonsoft.Json:

dynamic stuff = Newtonsoft.Json.JsonConvert.DeserializeObject("{ color: 'red', value: 5 }");
string color = stuff.color;
int value = stuff.value;
7

Самый простой способ -

Просто включите эту dll

используйте код, подобный этому

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

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.
6

Вы можете расширить JavaScriptSerializer, чтобы рекурсивно скопировать словарь, который он создал для объектов expando, и затем использовать их динамически:

static class JavaScriptSerializerExtensions
{
    public static dynamic DeserializeDynamic(this JavaScriptSerializer serializer, string value)
    {
        var dictionary = serializer.Deserialize<IDictionary<string, object>>(value);
        return GetExpando(dictionary);
    }

    private static ExpandoObject GetExpando(IDictionary<string, object> dictionary)
    {
        var expando = (IDictionary<string, object>)new ExpandoObject();

        foreach (var item in dictionary)
        {
            var innerDictionary = item.Value as IDictionary<string, object>;
            if (innerDictionary != null)
            {
                expando.Add(item.Key, GetExpando(innerDictionary));
            }
            else
            {
                expando.Add(item.Key, item.Value);
            }
        }

        return (ExpandoObject)expando;
    }
}

Затем вам просто нужно иметь оператор using для пространства имен, в котором вы указали расширение (рассмотрите только определение их в System.Web.Script.Serialization... еще один трюк заключается в том, чтобы не использовать пространство имен, тогда вы не вообще-то нужно использовать инструкцию), и вы можете использовать их так:

var serializer = new JavaScriptSerializer();
var value = serializer.DeserializeDynamic("{ 'Name': 'Jon Smith', 'Address': { 'City': 'New York', 'State': 'NY' }, 'Age': 42 }");

var name = (string)value.Name; // Jon Smith
var age = (int)value.Age;      // 42

var address = value.Address;
var city = (string)address.City;   // New York
var state = (string)address.State; // NY
5

Вы можете использовать using Newtonsoft.Json

var jRoot = 
 JsonConvert.DeserializeObject<dynamic>(Encoding.UTF8.GetString(resolvedEvent.Event.Data));

resolvedEvent.Event.Data - это мой ответ от вызова основного события.

5

Я использую: http://json2csharp.com/, чтобы получить класс, представляющий объект Json.

Входные данные:

{
   "name":"John",
   "age":31,
   "city":"New York",
   "Childs":[
      {
         "name":"Jim",
         "age":11
      },
      {
         "name":"Tim",
         "age":9
      }
   ]
}

Вывод:

public class Child
{
    public string name { get; set; }
    public int age { get; set; }
}

public class Person
{
    public string name { get; set; }
    public int age { get; set; }
    public string city { get; set; }
    public List<Child> Childs { get; set; }
}

После этого я использую Newtonsoft.Json для заполнения класса:

using Newtonsoft.Json;

namespace GitRepositoryCreator.Common
{
    class JObjects
    {
        public static string Get(object p_object)
        {
            return JsonConvert.SerializeObject(p_object);
        }
        internal static T Get<T>(string p_object)
        {
            return JsonConvert.DeserializeObject<T>(p_object);
        }
    }
}

Вы можете назвать это так:

Person jsonClass = JObjects.Get<Person>(stringJson);

string stringJson = JObjects.Get(jsonClass);

PS:

Если имя переменной json не является допустимым именем С# (имя начинается с $), вы можете исправить это следующим образом:

public class Exception
{
   [JsonProperty(PropertyName = "$id")]
   public string id { get; set; }
   public object innerException { get; set; }
   public string message { get; set; }
   public string typeName { get; set; }
   public string typeKey { get; set; }
   public int errorCode { get; set; }
   public int eventId { get; set; }
}
5

Я использую это в своем коде и отлично работает

using System.Web.Script.Serialization;
JavaScriptSerializer oJS = new JavaScriptSerializer();
RootObject oRootObject = new RootObject();
oRootObject = oJS.Deserialize<RootObject>(Your JSon String);
  • 1
    но вопрос не в этом. есть разное, когда нужно указать тип для каждой строки json и работать с динамическим типом.
5

Для этого я бы использовал JSON.NET для синтаксического анализа низкого уровня потока JSON, а затем создавал иерархию объектов из экземпляров класса ExpandoObject.

4

Deserializing в JSON.NET может быть динамическим, используя класс JObject, который включен в эту библиотеку. Моя строка JSON представляет эти классы:

public class Foo {
   public int Age {get;set;}
   public Bar Bar {get;set;}
}

public class Bar {
   public DateTime BDay {get;set;}
}

Теперь мы десериализуем строку БЕЗ ссылок на вышеуказанные классы:

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

Для получения полного примера см. post.

4

использовать DataSet (С#) с помощью javascript простая функция для создания потока json с вводом DataSet создать json like (набор данных с несколькими таблицами) [[{А: 1, б: 2, с: 3}, {а: 3, б: 5, с: 6}], [{а: 23, B: 45, с: 35}, {а: 58, B: 59, с: 45}]]

только клиентская сторона использует eval, например

var d = eval ('[[{a: 1, b: 2, c: 3}, {a: 3, b: 5, c: 6}], [{a: 23, b: 45, C: 35}, {а: 58, B: 59, с: 45}]] ')

затем используйте

d [0] [0].a//out 1 из таблицы 0 строка 0

d [1] [1].b//out 59 из таблицы 1 строка 1

//create by Behnam Mohammadi And Saeed Ahmadian
public string jsonMini(DataSet ds)
{
    int t=0, r=0, c=0;
    string stream = "[";

    for (t = 0; t < ds.Tables.Count; t++)
    {
        stream += "[";
        for (r = 0; r < ds.Tables[t].Rows.Count; r++)
        {
            stream += "{";
            for (c = 0; c < ds.Tables[t].Columns.Count; c++)
            {
                stream += ds.Tables[t].Columns[c].ToString() + ":'" + ds.Tables[t].Rows[r][c].ToString() + "',";
            }
            if(c>0)
                stream = stream.Substring(0, stream.Length - 1);
            stream += "},";
        }
        if(r>0)
            stream = stream.Substring(0, stream.Length - 1);
        stream += "],";
    }
    if(t>0)
        stream = stream.Substring(0, stream.Length - 1);
    stream += "];";
    return stream;
}
4

Посмотрите на статью, которую я написал в CodeProject, которая точно отвечает на вопрос:

Динамические типы с JSON.NET

Существует слишком много для повторной публикации всего этого, и даже меньше, поскольку в этой статье есть вложение с ключом/требуемым исходным файлом.

  • 10
    Посмотрите на stackoverflow.com/questions/how-to-answer : Provide context for links A link to a potential solution is always welcome, but please add context around the link so your fellow users will have some idea what it is and why it's there
4

Существует легкая библиотека json для С#, называемая SimpleJson, которую можно найти в http://simplejson.codeplex.com https://github.com/facebook-csharp-sdk/simple-json

Он поддерживает .net 3.5+, silverlight и Windows 7 телефона.

Поддерживает динамику для .net 4.0

Также может быть установлен как пакет nuget

Install-Package SimpleJson
4

Возможно, вам немного поздно помочь вам, но объект, который вы хотите, DynamicJSONObject включен в System.Web.Helpers.dll из пакета веб-страниц ASP.NET, который является частью WebMatrix.

3

попробуйте это -

  var units = new { Name = "Phone", Color= "White" };
    var jsonResponse = JsonConvert.DeserializeAnonymousType(json, units );
3

Чтобы получить объект ExpandoObject:

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

Container container = JsonConvert.Deserialize<Container>(jsonAsString, new ExpandoObjectConverter());
1

Как разобрать простой json с динамическим & JavaScriptSerializer

Добавьте ссылку System.Web.Extensions и добавьте это пространство имен using System.Web.Script.Serialization; наверху

public static void EasyJson()
{
    var jsonText = @"{
        ""some_number"": 108.541, 
        ""date_time"": ""2011-04-13T15:34:09Z"", 
        ""serial_number"": ""SN1234""
    }";

    var jss = new JavaScriptSerializer();
    var dict = jss.Deserialize<dynamic>(jsonText);

    Console.WriteLine(dict["some_number"]); 
    Console.ReadLine();
}

Как разобрать вложенный и сложный json с помощью dynamic & JavaScriptSerializer

Добавьте ссылку System.Web.Extensions и добавьте это пространство имен using System.Web.Script.Serialization; наверху

public static void ComplexJson()
{
    var jsonText = @"{
        ""some_number"": 108.541, 
        ""date_time"": ""2011-04-13T15:34:09Z"", 
        ""serial_number"": ""SN1234"",
        ""more_data"": {
            ""field1"": 1.0,
            ""field2"": ""hello""
        }
    }";

    var jss = new JavaScriptSerializer();
    var dict = jss.Deserialize<dynamic>(jsonText);

    Console.WriteLine(dict["some_number"]); 
    Console.WriteLine(dict["more_data"]["field2"]);
    Console.ReadLine();
}
1

Другой вариант - "Вставить JSON в качестве классов", чтобы его можно было десериализовать быстро и просто.

  1. Просто скопируйте весь JSON
  2. В VS: нажмите "Редактирование"> "Вставить"> "Вставить" JSON в качестве классов

Вот лучшее объяснение n piccas... https://blogs.msdn.microsoft.com/webdev/2012/12/18/paste-json-as-classes-in-asp-net-and-web-tools- 2012-2-гс/

0

С Cinchoo ETL - библиотека с открытым исходным кодом, доступная для синтаксического анализа json в динамическом объекте

string json = @"{
    ""key1"": [
        {
            ""action"": ""open"",
            ""timestamp"": ""2018-09-05 20:46:00"",
            ""url"": null,
            ""ip"": ""66.102.6.98""
        }
    ]
}";
using (var p = ChoJSONReader.LoadText(json)
    .WithJSONPath("$.*")
    )
{
    foreach (var rec in p)
    {
        Console.WriteLine("action: " + rec.action);
        Console.WriteLine("timestamp: " + rec.timestamp);
        Console.WriteLine("url: " + rec.url);
        Console.WriteLine("ip: " + rec.ip);
    }
}

Выход:

action: open
timestamp: 2018-09-05 20:46:00
url: http://www.google.com
ip: 66.102.6.98

Отказ от ответственности: я являюсь автором этой библиотеки.

0

используйте код ниже, который приведен в изображении ниже. Изображение 1001

Ещё вопросы

Сообщество Overcoder
Наверх
Меню