关于.NET:将JSON反序列化为C#动态对象?

Deserialize JSON into C# dynamic object?

是否有方法将JSON内容反序列化为C 4动态类型?为了使用DataContractJSonserializer,最好跳过创建一组类。


如果您愿意依赖System.Web.Helpers组件,则可以使用Json类:

1
dynamic data = Json.Decode(json);

它包含在MVC框架中,作为对.NET 4框架的附加下载。如果有帮助的话,一定要给vlad一个赞成票!但是,如果您不能假定客户机环境包含此dll,则继续阅读。

这里建议使用另一种反序列化方法。我稍微修改了代码以修复bug并适应我的编码风格。您所需要的只是这个代码和项目中对System.Web.Extensions的引用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
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
}

您可以这样使用它:

1
2
3
4
5
6
string json = ...;

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

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

因此,给定一个JSON字符串:

1
2
3
4
5
6
7
{
 "Items":[
    {"Name":"Apple","Price":12.3 },
    {"Name":"Grape","Price":3.21 }
  ],
 "Date":"21/11/2010"
}

以下代码将在运行时工作:

1
2
3
4
5
6
7
8
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)


使用json.net非常简单:

1
2
3
4
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

1
2
3
4
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


您可以使用system.web.helpers.json来实现这一点——它的decode方法返回一个动态对象,您可以根据需要遍历该对象。

它包含在system.web.helpers程序集(.net 4.0)中。

1
var dynamicObject = Json.Decode(jsonString);


.NET 4.0有一个内置库来执行此操作:

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

这是最简单的方法。


简单的"string json data"到不带任何第三方dll文件的对象:

1
2
3
4
5
6
7
8
9
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

注意:您也可以使用自定义对象。

1
Personel item = serializer.Deserialize<Personel>(getString);


JSonfx可以将JSON内容反序列化为动态对象。

Serialize to/from dynamic types (default for .NET 4.0):

1
2
3
4
5
6
7
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]}

我制作了一个使用Expando对象的动态JSonConverter的新版本。我使用expando对象,因为我想使用json.net将动态序列化回json。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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) })); }
        }
    }
}

使用newtonsoft.json的另一种方法:

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

最简单的方法是:

只包括这个dll文件。

使用如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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.


您可以扩展javascriptserializer以递归地复制它创建的字典以扩展对象,然后动态地使用它们:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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中定义它们…另一个技巧是不使用名称空间,那么根本不需要using语句),您可以这样使用它们:

1
2
3
4
5
6
7
8
9
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

您可以使用using Newtonsoft.Json

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

resolvedEvent.Event.Data是我从呼叫核心事件得到的响应。


我在我的代码中使用这样的代码,它工作正常

1
2
3
4
using System.Web.Script.Serialization;
JavaScriptSerializer oJS = new JavaScriptSerializer();
RootObject oRootObject = new RootObject();
oRootObject = oJS.Deserialize<RootObject>(Your JSon String);


为此,我将使用json.net对json流进行低级解析,然后用ExpandoObject类的实例构建对象层次结构。


看看我在codeproject上写的文章,它精确地回答了这个问题:

带有json.net的动态类型

在这里重新发布的内容太多了,甚至更少,因为该文章有一个带有键/必需源文件的附件。


我使用http://json2charp.com/获取表示JSON对象的类。

输入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
  "name":"John",
  "age":31,
  "city":"New York",
  "Childs":[
      {
        "name":"Jim",
        "age":11
      },
      {
        "name":"Tim",
        "age":9
      }
   ]
}

输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
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来填充这个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);
        }
    }
}

你可以这样称呼它:

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

string stringJson = JObjects.Get(jsonClass);

PS:

如果您的JSON变量名不是有效的C名(名称以$开头),您可以这样修复它:

1
2
3
4
5
6
7
8
9
10
11
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; }
}

试试这个:

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

json.net中的反序列化可以使用该库中包含的JObject类实现动态。我的JSON字符串代表这些类:

1
2
3
4
5
6
7
8
public class Foo {
   public int Age {get;set;}
   public Bar Bar {get;set;}
}

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

现在我们反序列化字符串而不引用上述类:

1
2
3
4
5
6
7
8
9
10
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());

或者如果你想更深入:

1
2
3
4
5
6
7
8
9
10
11
12
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了解完整的示例。


将数据集(c)与JavaScript一起使用。用于创建带有数据集输入的JSON流的简单函数。创建JSON内容,如(多表数据集):

1
[[{a:1,b:2,c:3},{a:3,b:5,c:6}],[{a:23,b:45,c:35},{a:58,b:59,c:45}]]

只是客户端,使用eval。例如,

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

然后使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
d[0][0].a // out 1 from table 0 row 0

d[1][1].b // out 59 from table 1 row 1

// Created 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 +=
<hr><P>有一个轻量级的C JSON库,称为simpleJSON。</P><P>它支持.NET 3.5+、Silverlight和Windows Phone 7</P><P>它支持.NET 4.0的动态</P><P>它也可以作为nuget包安装</P>[cc lang="csharp"]Install-Package SimpleJson


希望使用dynamicjsonObject的对象包含在ASP.NET网页包的system.web.helpers.dll中,该包是WebMatrix的一部分。


To get an ExpandoObject:

1
2
3
4
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;

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

如何使用动态javascriptserializer解析简单的JSON内容

请添加system.web.extensions的引用,并在顶部添加此命名空间using System.Web.Script.Serialization;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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();
}

如何使用动态javascriptserializer解析嵌套的复杂JSON

请添加system.web.extensions的引用,并在顶部添加此命名空间using System.Web.Script.Serialization;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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();
}

另一个选项是"将JSON粘贴为类",以便快速轻松地反序列化它。

  • 只需复制整个JSON
  • 在Visual Studio中:单击"编辑"&rarr;"选择性粘贴"&rarr;"将JSON粘贴为类"
  • 这是一个更好的解释。在ASP.NET和Web工具2012.2 rc中"将JSON粘贴为类"


    使用Cinchoo ETL——一个可用于将JSON解析为动态对象的开放源代码库:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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 address:" + rec.ip);
        }
    }

    输出:

    1
    2
    3
    4
    Action: open
    Timestamp: 2018-09-05 20:46:00
    URL: http://www.google.com
    IP address: 66.102.6.98

    免责声明:我是这个图书馆的作者。