将JSON反序列化为C#动态对象?[复制]

Deserialize JSON into C# dynamic object? [duplicate]

提问人:jswanson 提问时间:6/30/2010 最后编辑:John Smithjswanson 更新时间:6/14/2023 访问量:1105172

问:

有没有办法将JSON内容反序列化为C#动态类型?跳过创建一堆类以使用 .DataContractJsonSerializer

C# .NET JSON 序列化 动态

评论

7赞 6/30/2010
如果你想要一些“动态”的东西,为什么不直接使用大多数 JSON 解码器附带的 get-style 访问器,这些访问器不会转到 plain-old-object?(例如,真的需要创建“动态”对象吗?json.org 有一堆 C# JSON 实现的链接。
0赞 jswanson 6/30/2010
我正在做一个试图将外部依赖关系保持在最低限度的项目。因此,如果有可能使用首选的库存 .net 序列化程序和类型。当然,如果不可能,我会打 json.org。谢谢!
54赞 Frank Schwieterman 7/21/2010
我真的很惊讶 C# 团队添加了“动态”,但是 CLR 中没有办法将 JSON 对象转换为动态 CLR 类实例。
0赞 Tonecops 3/5/2023
你应该知道我偶然发现的事情:我真的很幸运,只有在我已经使用Edit >'Paste Special'->'Paste JSON as Classes'在Visual Studio中创建了类之后,我才找到了这个很棒的线程。创建这样的类使智能感知能够完美地适用于给定的 json 结构。这是绝对必要的,因为 json 字符串是巨大的 -370k。这是关于使用“ytdlp --dump-json”的 youtube 视频的大信息转储,具有数十个 json 项目。

答:

4赞 Daniel Earwicker 6/30/2010 #1

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

评论

1赞 singhswat 5/27/2021
一个例子将帮助更广泛的受众
735赞 Drew Noakes 9/28/2010 #2

如果您乐于依赖程序集,则可以使用 Json 类:System.Web.Helpers

dynamic data = Json.Decode(json);

它作为 .NET 4 框架的附加下载包含在 MVC 框架中。如果有帮助,一定要给弗拉德投赞成票!但是,如果您不能假定客户端环境包含此 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)

评论

3赞 Stewie Griffin 6/19/2011
我在动态 obj = 序列化程序中出现错误。反序列化(json, typeof(object));说带有 2 个参数的方法没有重载。.错误的DLL还是什么?
3赞 Quantumplation 12/18/2011
我发现你的ToString方法对我不起作用,所以我重写了它。它可能有一些错误,但它正在我的数据集上运行,所以我将在这里为可能遇到问题的任何其他人提供它:pastebin.com/BiRmQZdz
39赞 Vlad Iliescu 2/29/2012
可以使用 System.Web.Helpers.Json - 它提供返回动态对象的 Decode 方法。我也发布了此信息作为答案。
2赞 Radu Simionescu 9/28/2012
有时在 JS 中,你有带有特殊字符的字段,例如“background-color”。要在 js 中访问此类字段,请执行 obj[“background-color”]。反序列化为动态对象后,如何从 c# 访问此类字段?当然,我不能做obj.background-color,obj[“background-color”]似乎不起作用。如果动态对象也可以作为字典访问,那就太好了,就像在 js 中一样。
2赞 Martin Ender 1/20/2013
@RaduSimionescu我可能有点晚了,但也许这对未来的游客有帮助。我遇到了同样的问题,只是字段名称(这是 C# 中的一个关键字)。此外,您还可以覆盖 ,这为您提供了与 JS 中完全相同的行为。然后,您可以对笨拙的字段名称执行 OR。paramsTryGetMemberTryGetIndexobj["params"]obj["background-color"]
4赞 Nick Daniels 12/21/2010 #3

所需的对象 DynamicJSONObject 包含在 ASP.NET Web Pages 包中的 System.Web.Helpers.dll 中,该包是 WebMatrix 的一部分。

29赞 jbtule 3/2/2011 #4

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

序列化为动态类型/从动态类型序列化(.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]}
4赞 prabir 5/30/2011 #5

C# 有一个轻量级的 JSON 库,称为 SimpleJson

它支持 .NET 3.5+、Silverlight 和 Windows Phone 7。

它支持 .NET 4.0 的动态

它也可以作为 NuGet 包安装

Install-Package SimpleJson

评论

0赞 Fandango68 3/6/2021
是的,但是你如何使用它呢?回答不力
20赞 Jason Bolton 6/7/2011 #6

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

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) })); }
        }
    }
}
87赞 Peter Long 6/12/2011 #7

.NET 4.0 有一个内置库来执行此操作:.NET 4.0 has a built-in library to do this:

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

这是最简单的方法。

评论

29赞 sergiopereira 6/13/2011
你试过这个吗?它返回 .除非我遗漏了某些内容,否则您的示例不会返回动态对象。Dictionary<string,object>
19赞 mattmanser 6/30/2011
这是行不通的,它只是以动态的形式返回一个字典
56赞 mattmanser 7/1/2011
@Peter 很长一段时间,我相信我没有清楚地陈述我的情况,亲爱的家伙。让我尝试纠正我的错误。我知道什么是动态。这不允许你传入一个JSON对象并使用d.code,你必须执行d[“code”]。价值,这不是大多数找到这个答案的人想要的,我们已经知道如何获取字典并将其转换为动态完全是浪费时间。我恭敬地不同意,先生。
4赞 Peter Long 7/14/2011
@mattmanser、.它不一定是字典。除了字典之外,Json 还有列表。列表和字典也可以嵌套。我的代码可以处理所有这些情况。但是你的方法不能。we already know how to get the dictionary and casting it to a dynamic
4赞 Stephen Drew 10/23/2014
@mattmanser是对的;可以实现(或使用例如)能够截获属性并在内部字典中查找它们。这与允许使用诸如要使用的代码相结合。将字典投射到动态中是毫无意义的。IDynamicMetaObjectProviderExpandoObjectdynamicd.code
6赞 alonzofox 12/1/2011 #8

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

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 语句),你可以像这样使用它们:

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
747赞 Tom Peplow 2/17/2012 #9

使用 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

评论

16赞 Matthias 6/16/2014
@HotLicks:要反省动态,请执行以下操作:stuffforeach (Newtonsoft.Json.Linq.JProperty jproperty in stuff) { Console.WriteLine("jproperty.Name = {0}", jproperty.Name);}
12赞 cja 10/9/2014
JsonConvert.DeserializeObject 和 JObject.Parse 有什么区别?答案是以相同的方式使用它们来做同样的事情,但不能解释其中的区别。
11赞 Lee Louviere 2/19/2015
@TomPeplow 试过这个。它对我不起作用。它说“JObject 没有实现 'Name'”。
5赞 nawfal 6/15/2015
@cja没什么区别:stackoverflow.com/questions/23645034/......
13赞 codeConcussion 12/12/2015
我无法让它工作。我已将问题范围缩小到方法内部。如果我使方法同步,它将按预期工作。但是,制定方法,我得不到一个,我只得到一个.显式铸造什么也没做,仍然只是给我一个.还有其他人遇到这种情况吗?asyncasyncdynamicobjectobject
311赞 Vlad Iliescu 2/29/2012 #10

可以使用 System.Web.Helpers.Json 执行此操作 - 其 Decode 方法返回一个动态对象,您可以根据需要遍历该对象。

它包含在 System.Web.Helpers 程序集 (.NET 4.0) 中。

var dynamicObject = Json.Decode(jsonString);

评论

29赞 jbtule 3/31/2012
仅供参考 System.Web.Helpers.dll 需要 .net 4.0,但不包含在 .net 4.0 中。它可以与 ASP.NET MVC 3 一起安装
7赞 W3Max 1/17/2013
您将在 Visual Studio 2012 中“程序集”下的“扩展”组中找到此程序集
1赞 Usama Khalil 4/15/2013
使用动态有什么问题吗?如果输入 JSON 不包含属性,我们如何有效地处理异常。.
5赞 Mike 4/16/2013
如果要对模型进行强类型化,请确保使用 Json.Decode<T>(string) 方法。
2赞 7/11/2014
要将此库添加到您的项目中,请执行以下操作: stackoverflow.com/questions/8037895/...
89赞 İbrahim Özbölük 11/30/2012 #11

简单的“字符串 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);

评论

5赞 cikatomo 2/20/2013
我不明白。这是迄今为止最简单的解决方案,没有人提到它。
2赞 İbrahim Özbölük 8/6/2013
是的,这很简单:)有时您需要序列化,但不想包含第 3 部分 DLL
0赞 Royi Namir 9/20/2013
您能否详细说明:如何动态地通过 : 访问反序列化对象?我知道它是在运行时完成的,但是如何通过访问它是有效的?myObject["myprop"]myObject["myprop"]
1赞 İbrahim Özbölük 9/20/2013
您可以像 Personel item = serializer 一样反序列化您的对象。反序列化<Personel>(getString);如果你使用动态对象,你也可以使用数组,一切皆有可能,就像每个对象一样
3赞 StilgarISCA 9/8/2018
若要使用 System.Web.Script.Serialization 命名空间,项目需要引用 System.Web.Extensions。
8赞 user1006544 12/26/2012 #12

最简单的方法是:

只需包含此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.
26赞 Jonas Lundgren 4/10/2013 #13

使用 Newtonsoft.Json 的另一种方法:

dynamic stuff = Newtonsoft.Json.JsonConvert.DeserializeObject("{ color: 'red', value: 5 }");
string color = stuff.color;
int value = stuff.value;
5赞 vitaly-t 8/5/2013 #14

看看我在CodeProject上写的那篇文章,它准确地回答了这个问题:

具有 JSON.NET 的动态类型

在这里重新发布它太多了,甚至更少,因为该文章有一个带有密钥/所需源文件的附件。

4赞 Behnam 1/28/2014 #15

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

[[{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。例如

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}]]')

然后使用:

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 += "},";
        }
        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赞 Ryan Norbauer 3/4/2014 #16

若要获取 ExpandoObject,请执行以下操作:

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

Container container = JsonConvert.Deserialize<Container>(jsonAsString, new ExpandoObjectConverter());
6赞 Nirupam 3/7/2015 #17

试试这个:

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

评论

0赞 znn 6/10/2021
到目前为止我最喜欢的方法
0赞 Shahroozevsky 7/18/2021
伙计,+1 拥抱你:D
5赞 2Yootz 7/30/2015 #18

JSON.NET 中的反序列化可以使用该库中包含的类进行动态。我的 JSON 字符串表示这些类:JObject

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

有关完整示例,请参阅帖子

评论

0赞 Alex 75 12/21/2019
这种方法允许“遍历”jSON文档,以便您可以管理JSON结构未知或可变的情况(例如,许多API在发生错误时返回完全不同的JSON文档)。除了 Newtonsoft.JSON(又名 JSON.NET)之外,还有其他库允许这样做?
5赞 Vasim Shaikh 8/11/2015 #19

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

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

评论

1赞 Illuminati 6/7/2016
但这不是问题所要问的。当您必须为每个 JSON 字符串指定类型并使用动态类型时,情况会有所不同。
12赞 RoJaIt 6/11/2017 #20

我使用 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);

附言:

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

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; }
}
6赞 Vivek Shukla 6/26/2017 #21

你可以使用using Newtonsoft.Json

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

resolvedEvent.Event.Data是我从调用核心事件中得到的回应。

8赞 nitsram 3/17/2018 #22

另一种选择是“将 JSON 粘贴为类”,以便可以快速轻松地对其进行反序列化。

  1. 只需复制整个 JSON 即可
  2. 在 Visual Studio 中:单击“编辑”→“选择性粘贴”→“将 JSON 粘贴为类

这是一个更好的解释 n piccas...ASP.NET 和 Web 工具 2012.2 RC 中的“将 JSON 粘贴为类”

4赞 Mist 5/21/2018 #23

如何使用 dynamic 和 JavaScriptSerializer 解析简单的 JSON 内容

请添加 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();
}

如何使用动态和JavaScriptSerializer解析嵌套和复杂的json

请添加 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();
}
3赞 Cinchoo 9/7/2018 #24

使用 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("$..key1")
    )
{
    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);
    }
}

输出:

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

小提琴样本:https://dotnetfiddle.net/S0ehSV

有关更多信息,请访问 codeproject 文章

免责声明:我是这个库的作者。

2赞 LoremIpsum 6/17/2019 #25

试试这个方法!

JSON 示例:

[{
    "id": 140,
    "group": 1,
    "text": "xxx",
    "creation_date": 123456,
    "created_by": "[email protected]",
    "tags": ["xxxxx"]
  }, {
    "id": 141,
    "group": 1,
    "text": "xxxx",
    "creation_date": 123456,
    "created_by": "[email protected]",
    "tags": ["xxxxx"]
}]

C# 代码:

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()}");
}
46赞 Waleed Naveed 8/2/2019 #26

您可以在 Newtonsoft.Json 的帮助下实现这一点。从 NuGet 安装它,然后:

using Newtonsoft.Json;

dynamic results = JsonConvert.DeserializeObject<dynamic>(YOUR_JSON);
14赞 akac 8/18/2020 #27

使用 Newtonsoft.Json 创建动态对象的效果非常好。

//json is your string containing the JSON value
dynamic data = JsonConvert.DeserializeObject<dynamic>(json);

现在,您可以像访问常规对象一样访问该对象。这是我们目前作为示例的 JSON 对象:data

{ "ID":123,"Name":"Jack","Numbers":[1, 2, 3] }

这是反序列化后访问它的方式:

data.ID //Retrieve the int
data.Name //Retrieve the string
data.Numbers[0] //Retrieve the first element in the array
5赞 Billy Jake O'Connor 9/23/2020 #28

我想在单元测试中以编程方式做到这一点,我确实有幸将其输入出来。

我的解决方案是:

var dict = JsonConvert.DeserializeObject<ExpandoObject>(json) as IDictionary<string, object>;

现在我可以断言

dict.ContainsKey("ExpectedProperty");
32赞 Tengiz 12/23/2021 #29

我来这里是为了寻找 .NET Core 的答案,没有任何第三方或其他参考。如果您与标准类一起使用,它可以正常工作。这是对我有用的示例:ExpandoObjectJsonSerializer

using System.Text.Json;
using System.Dynamic;

dynamic json = JsonSerializer.Deserialize<ExpandoObject>(jsonText);
Console.WriteLine(json.name);

此代码输出传入方法的 JSON 文本中存在的属性的字符串值。瞧 - 没有额外的库,什么都没有。只是 .NET core。nameDeserialize

编辑:带有嵌套元素的多个级别的 json 可能存在问题。适用于单层平面物体。

评论

0赞 Anirudha Gupta 2/12/2022
它在 .net 6 中不起作用,有什么想法吗?我想读取具有元素数组的属性。
0赞 Tengiz 2/14/2022
它仅适用于基元类型属性,因为 expando 对象处理按名称读取的属性并按原样返回值。问题是 Console.WriteLine 通过调用 ToString 将值转换为字符串,对于基元类型,ToString 将给出正确的值。对于数组,您可能看到的不是实际值,而是输出中的对象类型。
0赞 Mazdak Shojaie 4/10/2023
请注意,使用成本很高!ExpandoObject
0赞 Tugay ÜNER 6/27/2022 #30

我需要的是返回一个具有不同字段的 JSON 模型。 我的模型是这样的,但它可以改变。

{
    "employees":
    [
        { "name": "Darth", "surname": "Vader", "age": "27", "department": "finance"},
        { "name": "Luke", "surname": "Skywalker", "age": "25", "department": "IT"},
        { "name": "Han", "surname": "Solo", "age": "26", "department": "credit"}
    ]
}

获取数据值的列表

    JObject array = JObject.Parse(model.JsonData);
    var tableData = new List<JsonDynamicModel>();

    foreach (var objx in array.Descendants().OfType<JProperty>().Where(p => p.Value.Type != JTokenType.Array && p.Value.Type != JTokenType.Object))
            {
                var name = ((JValue)objx.Name).Value;
                var value = ((JValue)objx.Value).Value;
                if (tableData.FirstOrDefault(x => x.ColumnName == name.ToString()) == null)
                {
                    tableData.Add(new JsonDynamicModel
                    {
                        ColumnName = name.ToString(),
                        Values = new List<string> { value.ToString() },
                    });
                }
                else
                {
                    tableData.FirstOrDefault(x=>x.ColumnName == name.ToString()).Values.Add(value.ToString());
                }
            }

输出将如下所示。然后我将生成的模型转换为html表,我使用此方法创建了一个html表

// output
tableData[0].ColumnName -> "name";
tableData[0].Values -> {"Darth", "Luke", "Han" }
tableData[1].ColumnName -> "surname";
tableData[1].Values -> {"Vader", "Skywalker", "Solo" }
...
3赞 OKEEngine 8/4/2022 #31

我真的很喜欢System.Web.Helpers,

dynamic data = Json.Decode(json);

因为它支持以下用法

var val = data.Members.NumberTen;

var val data.Members["10"];

对System.Web.Helpers.DLL的引用真的很疯狂,它甚至对控制台和桌面应用程序都不友好。这是我直接从 https://github.com/mono/aspnetwebstack/tree/master/src/System.Web.Helpers 中提取与独立文件相同的功能的尝试(仅出于教育目的共享此文件)

// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Dynamic;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
using Microsoft.CSharp.RuntimeBinder;
using System.Web.Script.Serialization;
using System.IO;
using System.Collections;
using System.Linq;
using System.Globalization;

namespace System.Web.Helpers
{
    public static class Json
    {
        private static readonly JavaScriptSerializer _serializer = CreateSerializer();

        public static string Encode(object value)
        {
            // Serialize our dynamic array type as an array
            DynamicJsonArray jsonArray = value as DynamicJsonArray;
            if (jsonArray != null)
            {
                return _serializer.Serialize((object[])jsonArray);
            }

            return _serializer.Serialize(value);
        }

        public static void Write(object value, TextWriter writer)
        {
            writer.Write(_serializer.Serialize(value));
        }

        public static dynamic Decode(string value)
        {
            return WrapObject(_serializer.DeserializeObject(value));
        }

        public static dynamic Decode(string value, Type targetType)
        {
            return WrapObject(_serializer.Deserialize(value, targetType));
        }

        public static T Decode<T>(string value)
        {
            return _serializer.Deserialize<T>(value);
        }

        private static JavaScriptSerializer CreateSerializer()
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            serializer.RegisterConverters(new[] { new DynamicJavaScriptConverter() });
            return serializer;
        }
        internal class DynamicJavaScriptConverter : JavaScriptConverter
        {
            public override IEnumerable<Type> SupportedTypes
            {
                get
                {
                    yield return typeof(IDynamicMetaObjectProvider);
                    yield return typeof(DynamicObject);
                }
            }

            public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
            {
                throw new NotSupportedException();
            }

            public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
            {
                Dictionary<string, object> dictionary = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
                IEnumerable<string> memberNames = DynamicHelper.GetMemberNames(obj);
                foreach (string item in memberNames)
                {
                    dictionary[item] = DynamicHelper.GetMemberValue(obj, item);
                }

                return dictionary;
            }
        }
        internal static dynamic WrapObject(object value)
        {
            // The JavaScriptSerializer returns IDictionary<string, object> for objects
            // and object[] for arrays, so we wrap those in different dynamic objects
            // so we can access the object graph using dynamic
            var dictionaryValues = value as IDictionary<string, object>;
            if (dictionaryValues != null)
            {
                return new DynamicJsonObject(dictionaryValues);
            }

            var arrayValues = value as object[];
            if (arrayValues != null)
            {
                return new DynamicJsonArray(arrayValues);
            }

            return value;
        }

    }
    // REVIEW: Consider implementing ICustomTypeDescriptor and IDictionary<string, object>
    public class DynamicJsonObject : DynamicObject
    {
        private readonly IDictionary<string, object> _values;

        public DynamicJsonObject(IDictionary<string, object> values)
        {
            Debug.Assert(values != null);
            _values = values.ToDictionary(p => p.Key, p => Json.WrapObject(p.Value),
                                          StringComparer.OrdinalIgnoreCase);
        }

        public override bool TryConvert(ConvertBinder binder, out object result)
        {
            result = null;
            if (binder.Type.IsAssignableFrom(_values.GetType()))
            {
                result = _values;
            }
            else
            {
                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "HelpersResources.Json_UnableToConvertType", binder.Type));
            }
            return true;
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            result = GetValue(binder.Name);
            return true;
        }

        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            _values[binder.Name] = Json.WrapObject(value);
            return true;
        }

        public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
        {
            string key = GetKey(indexes);
            if (!String.IsNullOrEmpty(key))
            {
                _values[key] = Json.WrapObject(value);
            }
            return true;
        }

        public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
        {
            string key = GetKey(indexes);
            result = null;
            if (!String.IsNullOrEmpty(key))
            {
                result = GetValue(key);
            }
            return true;
        }

        private static string GetKey(object[] indexes)
        {
            if (indexes.Length == 1)
            {
                return (string)indexes[0];
            }
            // REVIEW: Should this throw?
            return null;
        }

        public override IEnumerable<string> GetDynamicMemberNames()
        {
            return _values.Keys;
        }

        private object GetValue(string name)
        {
            object result;
            if (_values.TryGetValue(name, out result))
            {
                return result;
            }
            return null;
        }
    }
    [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification = "This class isn't meant to be used directly")]
    public class DynamicJsonArray : DynamicObject, IEnumerable<object>
    {
        private readonly object[] _arrayValues;

        public DynamicJsonArray(object[] arrayValues)
        {
            Debug.Assert(arrayValues != null);
            _arrayValues = arrayValues.Select(Json.WrapObject).ToArray();
        }

        public int Length
        {
            get { return _arrayValues.Length; }
        }

        public dynamic this[int index]
        {
            get { return _arrayValues[index]; }
            set { _arrayValues[index] = Json.WrapObject(value); }
        }

        public override bool TryConvert(ConvertBinder binder, out object result)
        {
            if (_arrayValues.GetType().IsAssignableFrom(binder.Type))
            {
                result = _arrayValues;
                return true;
            }
            return base.TryConvert(binder, out result);
        }

        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            // Testing for members should never throw. This is important when dealing with
            // services that return different json results. Testing for a member shouldn't throw,
            // it should just return null (or undefined)
            result = null;
            return true;
        }

        public IEnumerator GetEnumerator()
        {
            return _arrayValues.GetEnumerator();
        }

        private IEnumerable<object> GetEnumerable()
        {
            return _arrayValues.AsEnumerable();
        }

        IEnumerator<object> IEnumerable<object>.GetEnumerator()
        {
            return GetEnumerable().GetEnumerator();
        }

        [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates", Justification = "This class isn't meant to be used directly")]
        public static implicit operator object[](DynamicJsonArray obj)
        {
            return obj._arrayValues;
        }

        [SuppressMessage("Microsoft.Usage", "CA2225:OperatorOverloadsHaveNamedAlternates", Justification = "This class isn't meant to be used directly")]
        public static implicit operator Array(DynamicJsonArray obj)
        {
            return obj._arrayValues;
        }
    }

    /// <summary>
    /// Helper to evaluate different method on dynamic objects
    /// </summary>
    public static class DynamicHelper
    {
        // We must pass in "object" instead of "dynamic" for the target dynamic object because if we use dynamic, the compiler will
        // convert the call to this helper into a dynamic expression, even though we don't need it to be.  Since this class is internal,
        // it cannot be accessed from a dynamic expression and thus we get errors.

        // Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
        public static bool TryGetMemberValue(object obj, string memberName, out object result)
        {
            try
            {
                result = GetMemberValue(obj, memberName);
                return true;
            }
            catch (RuntimeBinderException)
            {
            }
            catch (RuntimeBinderInternalCompilerException)
            {
            }

            // We catch the C# specific runtime binder exceptions since we're using the C# binder in this case
            result = null;
            return false;
        }

        // Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "We want to swallow exceptions that happen during runtime binding")]
        public static bool TryGetMemberValue(object obj, GetMemberBinder binder, out object result)
        {
            try
            {
                // VB us an instance of GetBinderAdapter that does not implement FallbackGetMemeber. This causes lookup of property expressions on dynamic objects to fail.
                // Since all types are private to the assembly, we assume that as long as they belong to CSharp runtime, it is the right one. 
                if (typeof(Binder).Assembly.Equals(binder.GetType().Assembly))
                {
                    // Only use the binder if its a C# binder.
                    result = GetMemberValue(obj, binder);
                }
                else
                {
                    result = GetMemberValue(obj, binder.Name);
                }
                return true;
            }
            catch
            {
                result = null;
                return false;
            }
        }

        // Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
        public static object GetMemberValue(object obj, string memberName)
        {
            var callSite = GetMemberAccessCallSite(memberName);
            return callSite.Target(callSite, obj);
        }

        // Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
        public static object GetMemberValue(object obj, GetMemberBinder binder)
        {
            var callSite = GetMemberAccessCallSite(binder);
            return callSite.Target(callSite, obj);
        }

        // dynamic d = new object();
        // object s = d.Name;
        // The following code gets generated for this expression:
        // callSite = CallSite<Func<CallSite, object, object>>.Create(Binder.GetMember(CSharpBinderFlags.None, "Name", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }));
        // callSite.Target(callSite, d);
        // typeof(Program) is the containing type of the dynamic operation.
        // Dev10 Bug 914027 - Changed the callsite's target parameter from dynamic to object, see comment at top for details
        public static CallSite<Func<CallSite, object, object>> GetMemberAccessCallSite(string memberName)
        {
            var binder = Binder.GetMember(CSharpBinderFlags.None, memberName, typeof(DynamicHelper), new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) });
            return GetMemberAccessCallSite(binder);
        }

        // Dev10 Bug 914027 - Changed the callsite's target parameter from dynamic to object, see comment at top for details
        public static CallSite<Func<CallSite, object, object>> GetMemberAccessCallSite(CallSiteBinder binder)
        {
            return CallSite<Func<CallSite, object, object>>.Create(binder);
        }

        // Dev10 Bug 914027 - Changed the first parameter from dynamic to object, see comment at top for details
        public static IEnumerable<string> GetMemberNames(object obj)
        {
            var provider = obj as IDynamicMetaObjectProvider;
            Debug.Assert(provider != null, "obj doesn't implement IDynamicMetaObjectProvider");

            Expression parameter = Expression.Parameter(typeof(object));
            return provider.GetMetaObject(parameter).GetDynamicMemberNames();
        }
    }

}