如何使用 C# 反序列化 JSON?

How can I deserialize JSON with C#?

提问人: 提问时间:7/8/2011 最后编辑:TylerH 更新时间:9/21/2023 访问量:1458111

问:

我有以下代码:

var user = (Dictionary<string, object>)serializer.DeserializeObject(responsecontent);

输入是 JSON,但未正确反序列化为对象。我应该如何正确地反序列化它?responsecontent

C# JSON 字典 反序列化

评论

7赞 Vamsi 7/8/2011
嘿,你可能想试试这个链接 techblog.procurios.nl/k/n618/news/view/14605/14863/...
47赞 nawfal 6/15/2015
There is in , there is in , there is in , in , 哎呀,MS 甚至决定在其 ASP.NET Web API 中包含第三方。如果您认为这还不够,MS 正在提出,但目前不适合食用。走的路 Microsoft 走的路....我选择最好看的命名空间。JsonSystem.Web.HelpersJsonQueryStringConverterSystem.ServiceModel.WebJavascriptSerializerSystem.Web.Script.SerializationDataContractJsonSerializerSystem.Runtime.Serialization.JsonJson.NETSystem.Json
1赞 nawfal 8/4/2015
为了完成,其中还有仅适用于 Windows 8 及更高版本。我很喜欢它。多发性硬化症正在执行一项任务:)JsonValueWindows.Data.Json
6赞 Ohad Schneider 8/20/2016
NewtonSoft 在他们的网站上有一个比较页面(可能有偏见,但仍然很有趣):newtonsoft.com/json/help/html/jsonnetvsdotnetserializers.htm。我特别喜欢无意义的字典序列化行:)

答:

433赞 MD Sayem Ahmed 7/8/2011 #1

我假设您没有使用 Json.NET(Newtonsoft.Json NuGet 包)。如果是这种情况,那么你应该尝试一下。

它具有以下特点:

  1. LINQ 转 JSON
  2. JsonSerializer,用于快速将 .NET 对象转换为 JSON 并再次转换回来
  3. Json.NET 可以选择生成格式良好的缩进 JSON 进行调试或显示
  4. 可以将 和 等属性添加到类中,以自定义类的序列化方式JsonIgnoreJsonProperty
  5. 能够将JSON与XML相互转换
  6. 支持多个平台:.NET、Silverlight 和 Compact Framework

请看下面的例子。在此示例中,JsonConvert 类用于将对象与 JSON 相互转换。为此,它有两种静态方法。它们是 SerializeObject(Object obj)DeserializeObject<T>(String json):

using Newtonsoft.Json;

Product product = new Product();
product.Name = "Apple";
product.Expiry = new DateTime(2008, 12, 28);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };

string json = JsonConvert.SerializeObject(product);
//{
//  "Name": "Apple",
//  "Expiry": "2008-12-28T00:00:00",
//  "Price": 3.99,
//  "Sizes": [
//    "Small",
//    "Medium",
//    "Large"
//  ]
//}

Product deserializedProduct = JsonConvert.DeserializeObject<Product>(json);

评论

22赞 Pedro Dusso 3/11/2013
如果我不知道目标的完整结构,我可以反序列化为类型变量吗?具体来说,我正在使用 Rally 用户故事,我想将它们转换为对象。var
1赞 Momin 12/31/2013
@PedroDusso你可以,这是完整的文档
3赞 T.J. Crowder 9/28/2015
@PeterWone:否,返回字符串 ,而不是日期。它可以变成 VIA ,但对日期一无所知。您必须传入一个 reviver,该 reviver 根据模式检查每个字符串值。JSON.parse('{"Expiry": "2008-12-28T00:00:00"}').Expiry"2008-12-28T00:00:00"Datenew Date(str)JSON.parse
0赞 Peter Wone 9/28/2015
@T.J.Crowder - 我的错。刚刚检查了一下,你不仅是对的,而且比这更糟糕(他死了,吉姆!),具有微妙的不对称不兼容:JSON.stringify 生成秒到小数点后 2 位“2015-09-28T01:08:03.704Z”,这混淆了由 new Date(string) 隐式调用的 Date.parse。编写修复并重载内置日期解析并不难,但让我们都只使用 Moment.js
3赞 Peter Wone 9/29/2015
由于 3.703 秒与 3 秒和 703 毫秒相同,并且分隔符是小数点后一位,所以我告诉你这是秒到小数点后三位。
66赞 ElonU Webdev 7/8/2011 #2

如果 .NET 4 可供你使用,请查看:http://visitmix.com/writings/the-rise-of-json (archive.org)

以下是该网站的片段:

WebClient webClient = new WebClient();
dynamic result = JsonValue.Parse(webClient.DownloadString("https://api.foursquare.com/v2/users/self?oauth_token=XXXXXXX"));
Console.WriteLine(result.response.user.firstName);

最后一个 Console.WriteLine 非常贴心......

评论

0赞 ElonU Webdev 12/7/2012
对不起,自从我最初回答以来,情况似乎发生了变化。我必须环顾四周,看看哪个库是正确的......
7赞 user989056 12/7/2012
期待您找到这个库。编辑:是这个吗:dynamicjson.codeplex.com
1赞 nawfal 8/4/2015
我不知道 ElonU 在这里是什么意思,但 Windows.Data.Json 中有“JsonValue”(仅适用于 Windows 8 及更高版本 - 很奇怪),System.Json 中也有相同的“JsonValue”,它仍处于预览状态,只有上帝知道它是否会出来。当谈到 Json,MS 让我感到困惑。
21赞 Pieter Germishuys 7/8/2011 #3

还可以查看 DataContractJsonSerializer

评论

1赞 Mahmoud Fayez 2/8/2013
这更好,因为它与 .NET 3.5 兼容
0赞 David 12/17/2016
它也比 JavaScriptSerializer 快得多,
0赞 Liam 1/18/2022
仅供参考,.Net Core 不再支持此功能。
364赞 Dmitry Pavlov 7/25/2013 #4

正如这里回答的那样 - 将 JSON 反序列化为 C# 动态对象?

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

或者使用 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;

评论

14赞 Dmitry Pavlov 1/4/2016
@MaxHodges,你是对的。我只是使用内联“魔术字符串”来演示如何解析 JSON 字符串值。不希望它看起来很复杂,有转义的双引号。在实际代码中,我们通常将 JSON 字符串作为变量从某个地方获取或作为参数传递。
5赞 Fil 7/18/2017
如果没有 .net 4,你就没有“dynamic”关键字。您可以使用“var stuff”进行声明,而不是“stuff”。名称“和”东西。Address.City“,分别有”stuff[“Name”]'和'stuff[“Address”][“City”]'。
3赞 Alex 7/18/2017
@Fil 这为您提供了 type 的值,并且您不能对 .objectobject
0赞 Patrick Beynio 6/29/2020
@Alex我很确定 Newtonsoft.Json 变体返回一个 JObject。另外,不要使用 Json.NET,甚至 VS 现在也使用 Newtonsoft.Json。现在甚至可以在 VSIX 中使用,而无需将其添加到包中
157赞 qqbenq 7/22/2014 #5

以下是一些不使用第三方库的选项:

// For that you will need to add reference to System.Runtime.Serialization
var jsonReader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(@"{ ""Name"": ""Jon Smith"", ""Address"": { ""City"": ""New York"", ""State"": ""NY"" }, ""Age"": 42 }"), new System.Xml.XmlDictionaryReaderQuotas());

// For that you will need to add reference to System.Xml and System.Xml.Linq
var root = XElement.Load(jsonReader);
Console.WriteLine(root.XPathSelectElement("//Name").Value);
Console.WriteLine(root.XPathSelectElement("//Address/State").Value);

// For that you will need to add reference to System.Web.Helpers
dynamic json = System.Web.Helpers.Json.Decode(@"{ ""Name"": ""Jon Smith"", ""Address"": { ""City"": ""New York"", ""State"": ""NY"" }, ""Age"": 42 }");
Console.WriteLine(json.Name);
Console.WriteLine(json.Address.State);

有关 System.Web.Helpers.Json 的详细信息,请参阅链接。

更新:如今,获取 NuGet 的最简单方法是使用 NuGet 包Web.Helpers


如果你不关心早期的 Windows 版本,可以使用 Windows.Data.Json 命名空间的类:

// minimum supported version: Win 8
JsonObject root = Windows.Data.Json.JsonValue.Parse(jsonString).GetObject();
Console.WriteLine(root["Name"].GetString());
Console.WriteLine(root["Address"].GetObject()["State"].GetString());

评论

1赞 Budda 8/5/2014
为什么我在 ASP.NET 网站 (4.5) 中看不到 System.Web.Helpers?XElement、XPathSelectElement 对于我的 VisualStudio 来说并不为人所知。如何教育它?
0赞 qqbenq 8/5/2014
好吧,您必须添加相应库的引用(如上面的评论中所写),有关详细信息,请参阅本文。此外,这个问题可能会引起人们的兴趣。
2赞 Alex 1/20/2015
我使用了这里描述的 Web.Helpers 方法,但遇到了这篇文章解决的问题:stackoverflow.com/questions/7066726/......
1赞 Shahid Neermunda 2/26/2016
它使用以下命名空间处理 WPF.By 使用 System.Runtime.Serialization.Json;使用 System.Xml.XPath;使用 System.Xml.Linq;
4赞 Liam 8/5/2016
Json.Net 不再是第三方组件。如今,Microsoft自己使用它。它是 Web API 上的默认 serilizer。
45赞 Sven Mawby 12/21/2014 #6

另一个本机解决方案不需要任何第三方库,但需要对 System.Web.Extensions 的引用,即 JavaScriptSerializer。这不是一个新的,而是自 3.5 以来非常未知的内置功能。

using System.Web.Script.Serialization;

..

JavaScriptSerializer serializer = new JavaScriptSerializer();
objectString = serializer.Serialize(new MyObject());

然后返回

MyObject o = serializer.Deserialize<MyObject>(objectString)

评论

2赞 Al Kepp 2/5/2015
这非常好,但它需要 Web 组件,所以不幸的是,它在 .NET 4.0 Client Profile 中不起作用,这是 Windows XP 的最后一个 .NET 版本。完全安装 .NET 是可能的,但许多人只使用 Client Profile。相比之下,即使在客户端配置文件中也支持 System.Runtime.Serialization.Json.DataContractJsonSerializer。
3赞 DonkeyMaster 4/15/2015
@fr34kyn01535:Windows XP 在桌面上拥有第二大市场份额。这是相关的。
0赞 Rich 4/20/2018
当我使用 JavaScriptSerializer 来消除我的对象时,它起作用了,但它错误地反序列化了我的日期。它应该是 2018 年 4 月 19 日凌晨 12:00,但反序列化为 2018 年 4 月 18 日晚上 08:00。NewtonSoft.Json.JsonConvert 按预期对其进行反序列化。
5赞 TargetofGravity 2/24/2015 #7

我认为 msdn 站点中的以下内容应该有助于为您正在寻找的内容提供一些本机功能。请注意,它是为 Windows 8 指定的。下面列出了该网站的一个此类示例。

JsonValue jsonValue = JsonValue.Parse("{\"Width\": 800, \"Height\": 600, \"Title\": \"View from 15th Floor\", \"IDs\": [116, 943, 234, 38793]}");
double width = jsonValue.GetObject().GetNamedNumber("Width");
double height = jsonValue.GetObject().GetNamedNumber("Height");
string title = jsonValue.GetObject().GetNamedString("Title");
JsonArray ids = jsonValue.GetObject().GetNamedArray("IDs");

它利用 Windows.Data.JSON 命名空间。

评论

6赞 watbywbarif 3/10/2015
不错,但“最低支持的客户端:Windows 8”
0赞 virtouso 3/12/2015
我认为它不再受支持,现在有 Newtonsoft JSON dll,我找不到 windows.data.json
3赞 TargetofGravity 3/13/2015
@virtouso,正如 watbywbarif 指出的那样,它实际上是相当新的,但是 Microsoft 提供的最低支持仅适用于 Windows 8。
11赞 Muhammad Awais 5/27/2016 #8

请尝试以下代码:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("URL");
JArray array = new JArray();
using (var twitpicResponse = (HttpWebResponse)request.GetResponse())
using (var reader = new StreamReader(twitpicResponse.GetResponseStream()))
{
    JavaScriptSerializer js = new JavaScriptSerializer();
    var objText = reader.ReadToEnd();

    JObject joResponse = JObject.Parse(objText);
    JObject result = (JObject)joResponse["result"];
    array = (JArray)result["Detail"];
    string statu = array[0]["dlrStat"].ToString();
}

评论

0赞 Chris Catignani 3/30/2020
这条线在做任何事情吗?JavaScriptSerializer js = new JavaScriptSerializer();提前致谢。
-1赞 cr1pto 6/2/2016 #9

我认为我见过的最好的答案是@MD_Sayem_Ahmed。

您的问题是“如何使用 C# 解析 Json”,但您似乎想要解码 Json。如果你想解码它,艾哈迈德的答案很好。

如果尝试 ASP.NET 在 Web Api 中完成此操作,最简单的方法是创建一个数据传输对象,该对象包含要分配的数据:

public class MyDto{
    public string Name{get; set;}
    public string Value{get; set;}
}

只需将 application/json 标头添加到请求中(例如,如果使用的是 Fiddler)。 然后 ASP.NET Web API 中使用它,如下所示:

//controller method -- assuming you want to post and return data
public MyDto Post([FromBody] MyDto myDto){
   MyDto someDto = myDto;
   /*ASP.NET automatically converts the data for you into this object 
    if you post a json object as follows:
{
    "Name": "SomeName",
      "Value": "SomeValue"
}
*/
   //do some stuff
}

当我在 Web API 中工作时,这对我有很大帮助,让我的生活变得超级轻松。

21赞 Zunair 8/8/2018 #10

System.Json 现在可以工作了...

安装 nuget https://www.nuget.org/packages/System.Json

PM> Install-Package System.Json -Version 4.5.0

示例

// PM>Install-Package System.Json -Version 4.5.0

using System;
using System.Json;

namespace NetCoreTestConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // Note that JSON keys are case sensitive, a is not same as A.

            // JSON Sample
            string jsonString = "{\"a\": 1,\"b\": \"string value\",\"c\":[{\"Value\": 1}, {\"Value\": 2,\"SubObject\":[{\"SubValue\":3}]}]}";

            // You can use the following line in a beautifier/JSON formatted for better view
            // {"a": 1,"b": "string value","c":[{"Value": 1}, {"Value": 2,"SubObject":[{"SubValue":3}]}]}

            /* Formatted jsonString for viewing purposes:
            {
               "a":1,
               "b":"string value",
               "c":[
                  {
                     "Value":1
                  },
                  {
                     "Value":2,
                     "SubObject":[
                        {
                           "SubValue":3
                        }
                     ]
                  }
               ]
            }
            */

            // Verify your JSON if you get any errors here
            JsonValue json = JsonValue.Parse(jsonString);

            // int test
            if (json.ContainsKey("a"))
            {
                int a = json["a"]; // type already set to int
                Console.WriteLine("json[\"a\"]" + " = " + a);
            }

            // string test
            if (json.ContainsKey("b"))
            {
                string b = json["b"];  // type already set to string
                Console.WriteLine("json[\"b\"]" + " = " + b);
            }

            // object array test
            if (json.ContainsKey("c") && json["c"].JsonType == JsonType.Array)
            {
                // foreach loop test
                foreach (JsonValue j in json["c"])
                {
                    Console.WriteLine("j[\"Value\"]" + " = " + j["Value"].ToString());
                }

                // multi level key test
                Console.WriteLine("json[\"c\"][0][\"Value\"]" + " = " + json["c"][0]["Value"].ToString());
                Console.WriteLine("json[\"c\"][0][\"Value\"]" + " = " + json["c"][1]["Value"].ToString());
                Console.WriteLine("json[\"c\"][1][\"SubObject\"][0][\"SubValue\"]" + " = " + json["c"][1]["SubObject"][0]["SubValue"].ToString());
            }

            Console.WriteLine();
            Console.Write("Press any key to exit.");
            Console.ReadKey();
        }
    }
}

评论

1赞 monkey0506 11/17/2019
试图找到一个如何正确使用现代 System.Json 的示例将我带到了这里,在 Json.NET/Newtonsoft.Json/“Newtson.Json”和 System.Json 的旧迭代早已弃用的无数结果之后。谢谢你。
1赞 Shaybc 6/20/2020
对于 dotnet-core,从终端执行:“dotnet add package System.Json --version 4.5.0”
14赞 Bruno Pereira 1/10/2019 #11

使用此工具生成基于 json 的类:

http://json2csharp.com/

然后使用该类对 json 进行反序列化。例:

public class Account
{
    public string Email { get; set; }
    public bool Active { get; set; }
    public DateTime CreatedDate { get; set; }
    public IList<string> Roles { get; set; }
}


string json = @"{
  'Email': '[email protected]',
  'Active': true,
  'CreatedDate': '2013-01-20T00:00:00Z',
  'Roles': [
    'User',
    'Admin'
  ]
}";

Account account = JsonConvert.DeserializeObject<Account>(json);

Console.WriteLine(account.Email);
// [email protected]

参考资料: https://forums.asp.net/t/1992996.aspx?Nested+Json+Deserialization+to+C+object+and+using+that+object https://www.newtonsoft.com/json/help/html/DeserializeObject.htm

-1赞 Fernando Meneses Gomes 6/29/2019 #12
         string json = @"{
            'Name': 'Wide Web',
            'Url': 'www.wideweb.com.br'}";

        JavaScriptSerializer jsonSerializer = new JavaScriptSerializer();
        dynamic j = jsonSerializer.Deserialize<dynamic>(json);
        string name = j["Name"].ToString();
        string url = j["Url"].ToString();
43赞 haldo 10/22/2019 #13

System.Text.Json

.NET core 3.0 内置了 System.Text.Json,这意味着无需使用第三方库即可反序列化/序列化 JSON。

序列化/反序列化

要将类序列化为 JSON 字符串,请执行以下操作:

var json = JsonSerializer.Serialize(model);

若要将 JSON 反序列化为强类型类,请执行以下操作:

var model = JsonSerializer.Deserialize<Model>(json);

分析 (.NET 6)Parse (.NET 6)

.NET 6 引入了 System.Text.Json.Nodes 命名空间,该命名空间支持使用 Newtonsoft.Json 使用新类 、 、 和 进行 DOM 解析、导航和操作。JsonObjectJsonArrayJsonValueJsonNode

// JsonObject parse DOM
var jsonObject = JsonNode.Parse(jsonString).AsObject();
// read data from DOM
string name = jsonObject["Name"].ToString();
DateTime date = (DateTime)jsonObject["Date"];
var people = jsonObject["People"].Deserialize<List<Person>>();

类似的方法也适用于 。此答案提供了有关 JsonObject 的更多详细信息。JsonArray


需要注意的一点是,在使用您自己的代码时它不会自动处理 JSON 属性(但是,在使用 MVC/WebAPI 请求和模型绑定器时,它会自动处理)。System.Text.JsoncamelCase

要解决此问题,您需要作为参数传递。JsonSerializerOptions

JsonSerializerOptions options = new JsonSerializerOptions
{        
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,  // set camelCase       
    WriteIndented = true                                // write pretty json
};

// pass options to serializer
var json = JsonSerializer.Serialize(order, options);
// pass options to deserializer
var order = JsonSerializer.Deserialize<Order>(json, options);

System.Text.Json 也可用于 .Net Framework 和 .Net Standard 作为 Nu-get 包 System.Text.Json

编辑

在 .NET 6 中,JsonNode.Parse() 提供了分析“未知”json 的功能

评论

3赞 Cherona 4/15/2020
如果你没有上课怎么办?如果您只是模糊地知道 json 数据将包含什么怎么办?或者钥匙是否存在?
5赞 haldo 4/15/2020
@Cherona使用 .JsonDocument.Parse
3赞 haldo 3/23/2022
在 .NET 6 中,提供了分析“未知”json 的功能JsonNode.Parse()
0赞 Hidayet R. Colkusu 5/24/2020 #14

您可以使用以下扩展名

public static class JsonExtensions
{
    public static T ToObject<T>(this string jsonText)
    {
        return JsonConvert.DeserializeObject<T>(jsonText);
    }

    public static string ToJson<T>(this T obj)
    {
        return JsonConvert.SerializeObject(obj);
    } 
}
11赞 Vikas Lalwani 7/14/2020 #15

如果 JSON 是动态的,如下所示

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

然后,从 NuGet 安装并将其包含在项目中后,可以将其序列化为NewtonSoft.Json

string jsonString = "{\"Items\": [{\"Name\": \"Apple\",\"Price\": 12.3},{\"Name\": \"Grape\",\"Price\": 3.21}],\"Date\": \"21/11/2010\"}";

        dynamic DynamicData = JsonConvert.DeserializeObject(jsonString);

        Console.WriteLine(   DynamicData.Date); // "21/11/2010"
        Console.WriteLine(DynamicData.Items.Count); // 2
        Console.WriteLine(DynamicData.Items[0].Name); // "Apple"

来源:如何在 C# 中读取 JSON 数据(使用控制台应用和 MVC ASP.NET 示例)?

0赞 Starnuto di topo 5/25/2022 #16

我最终得到了一个简单的类,该类可以动态创建类型,实例化它们并冻结它们,从而镜像输入 JSON 的结构。

在此处输入图像描述

你可以在这里找到它:

https://github.com/starnutoditopo/JsonToObject

JsonToObjectConverter.cs

using System.Globalization;
using System.Reflection;
using System.Reflection.Emit;
using System.Text.Json;

namespace JsonToObject;

/// <summary>Provides functionalities to convert JSON strings in to CLR objects.</summary>
public class JsonToObjectConverter
{
    private class Counter
    {
        private ulong count;
        public Counter()
        {
            this.count = 0;
        }

        public ulong Next()
        {
            this.count++;
            return this.count;
        }
    }


    private static ulong assemblyGenerationCounter;
    private readonly JsonToObjectConverterOptions options;

    static JsonToObjectConverter()
    {
        assemblyGenerationCounter = 0;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="JsonToObjectConverter" /> class, using default options.
    /// </summary>
    /// <param name="options">The options.</param>
    public JsonToObjectConverter()
        : this(new JsonToObjectConverterOptions())
    {
    }


    /// <summary>
    /// Initializes a new instance of the <see cref="JsonToObjectConverter" /> class, using the specified options.
    /// </summary>
    /// <param name="options">The options.</param>
    public JsonToObjectConverter(JsonToObjectConverterOptions options)
    {
        this.options = options;
    }

    /// <summary>Converts a JSON string to an instance of a CLR object.</summary>
    /// <param name="jsonString">The json string.</param>
    /// <returns>
    ///   <br />
    /// </returns>
    public object? ConvertToObject(string jsonString)
    {
        JsonSerializerOptions opt = new JsonSerializerOptions()
        {
            PropertyNameCaseInsensitive = true
        };
        JsonElement rawResult = JsonSerializer.Deserialize<JsonElement>(jsonString, opt);
        object? result = ToStronglyTypedObject(rawResult);
        return result;
    }

    private object? ToStronglyTypedObject(JsonElement? nullableJsonElement)
    {
        string assemblyNameString;
        ulong assemblyId = Interlocked.Increment(ref assemblyGenerationCounter);
        try
        {
            assemblyNameString = string.Format(this.options.RuntimeGeneratedAssemblyNameTemplate, assemblyId.ToString(CultureInfo.InvariantCulture));
        }
        catch
        {
            throw new InvalidOperationException($@"Unable to generate assembly name using template '{this.options.RuntimeGeneratedAssemblyNameTemplate}' and id '{assemblyId}'. Please, review the {nameof(JsonToObjectConverterOptions.RuntimeGeneratedAssemblyNameTemplate)} property in the options.");
        }
        ModuleBuilder moduleBuilder = CreateModuleBuilder(assemblyNameString, this.options.RuntimeGeneratedModuleName);
        Counter typeGenerationCounter = new Counter();
        var result = ToStronglyTypedObject(nullableJsonElement, moduleBuilder, typeGenerationCounter);
        return result;
    }
    private object? ToStronglyTypedObject(
        JsonElement? nullableJsonElement,
        ModuleBuilder moduleBuilder,
        Counter typeGenerationCounter
    )
    {
        if (nullableJsonElement == null)
        {
            return null;
        }

        JsonElement jsonElement = nullableJsonElement.Value;

        switch (jsonElement.ValueKind)
        {
            case JsonValueKind.Undefined:
                return null;
            case JsonValueKind.String:
                return jsonElement.GetString();
            case JsonValueKind.False:
                return false;
            case JsonValueKind.True:
                return true;
            case JsonValueKind.Null:
                return null;
            case JsonValueKind.Number:
                {
                    if (jsonElement.TryGetDouble(out var result))
                    {
                        return result;
                    }
                }
                throw new InvalidOperationException($"Unable to parse {jsonElement} as number.");
            case JsonValueKind.Object:
                {
                    ulong typeId = typeGenerationCounter.Next();
                    string typeName;
                    try
                    {
                        typeName = string.Format(this.options.RuntimeGeneratedTypeNameTemplate, typeId.ToString(CultureInfo.InvariantCulture));
                    }
                    catch
                    {
                        throw new InvalidOperationException($@"Unable to generate type name using template '{this.options.RuntimeGeneratedTypeNameTemplate}' and id '{typeId}'. Please, review the {nameof(JsonToObjectConverterOptions.RuntimeGeneratedTypeNameTemplate)} property in the options.");
                    }

                    TypeBuilder typeBuilder = CreateTypeBuilder(moduleBuilder, typeName);
                    Dictionary<string, object?> propertyValues = new Dictionary<string, object?>();
                    foreach (var property in jsonElement.EnumerateObject())
                    {
                        string propertyName = property.Name;
                        object? propertyValue = ToStronglyTypedObject(property.Value, moduleBuilder, typeGenerationCounter);
                        Type propertyValueType;
                        if (null == propertyValue)
                        {
                            propertyValueType = typeof(object);
                        }
                        else
                        {
                            propertyValueType = propertyValue.GetType();
                        }
                        CreateAutoImplementedProperty(typeBuilder, propertyName, propertyValueType);
                        propertyValues.Add(propertyName, propertyValue);
                    }

                    Type resultType = typeBuilder.CreateType()!;
                    object result = Activator.CreateInstance(resultType)!;
                    foreach (var pair in propertyValues)
                    {
                        var propertyInfo = resultType.GetProperty(pair.Key)!;
                        propertyInfo.SetValue(result, pair.Value);
                    }
                    return result;
                }
            case JsonValueKind.Array:
                {
                    List<object?> list = new List<object?>();
                    foreach (var item in jsonElement.EnumerateArray())
                    {
                        object? value = ToStronglyTypedObject(item, moduleBuilder, typeGenerationCounter);
                        list.Add(value);
                    }
                    return list.ToArray();
                }
            default:
                throw new InvalidOperationException($"Value type '{jsonElement.ValueKind}' is not supported");
        }
    }

    private static ModuleBuilder CreateModuleBuilder(
            string assemblyNameString,
            string moduleName
        )
    {
        // create assembly name
        var assemblyName = new AssemblyName(assemblyNameString);
        // create the assembly builder
        AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);

        // create the module builder
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(moduleName);
        return moduleBuilder;
    }

    private static TypeBuilder CreateTypeBuilder(
            ModuleBuilder moduleBuilder,
            string typeName
        )
    {
        // create the type builder
        TypeBuilder typeBuilder = moduleBuilder.DefineType(typeName, TypeAttributes.Public);
        typeBuilder.DefineDefaultConstructor(MethodAttributes.Public);
        return typeBuilder;
    }

    private static void CreateAutoImplementedProperty(
        TypeBuilder builder,
        string propertyName,
        Type propertyType
        )
    {
        const string PrivateFieldPrefix = "m_";
        const string GetterPrefix = "get_";
        const string SetterPrefix = "set_";

        // Generate the field.
        FieldBuilder fieldBuilder = builder.DefineField(
            string.Concat(PrivateFieldPrefix, propertyName),
                          propertyType, FieldAttributes.Private);

        // Generate the property
        PropertyBuilder propertyBuilder = builder.DefineProperty(
            propertyName, PropertyAttributes.HasDefault, propertyType, null);

        // Property getter and setter attributes.
        MethodAttributes propertyMethodAttributes =
            MethodAttributes.Public | MethodAttributes.SpecialName |
            MethodAttributes.HideBySig;

        // Define the getter method.
        MethodBuilder getterMethod = builder.DefineMethod(
            string.Concat(GetterPrefix, propertyName),
            propertyMethodAttributes, propertyType, Type.EmptyTypes);

        // Emit the IL code.
        // ldarg.0
        // ldfld,_field
        // ret
        ILGenerator getterILCode = getterMethod.GetILGenerator();
        getterILCode.Emit(OpCodes.Ldarg_0);
        getterILCode.Emit(OpCodes.Ldfld, fieldBuilder);
        getterILCode.Emit(OpCodes.Ret);

        // Define the setter method.
        MethodBuilder setterMethod = builder.DefineMethod(
            string.Concat(SetterPrefix, propertyName),
            propertyMethodAttributes, null, new Type[] { propertyType });

        // Emit the IL code.
        // ldarg.0
        // ldarg.1
        // stfld,_field
        // ret
        ILGenerator setterILCode = setterMethod.GetILGenerator();
        setterILCode.Emit(OpCodes.Ldarg_0);
        setterILCode.Emit(OpCodes.Ldarg_1);
        setterILCode.Emit(OpCodes.Stfld, fieldBuilder);
        setterILCode.Emit(OpCodes.Ret);

        propertyBuilder.SetGetMethod(getterMethod);
        propertyBuilder.SetSetMethod(setterMethod);
    }
}

JsonToObjectConverterOptions.cs

namespace JsonToObject;

/// <summary>
/// Defines the options to instantiate a <see cref="JsonToObjectConverter" /> object.
/// </summary>
public class JsonToObjectConverterOptions
{
    private const string CONSTANTS_RuntimeGeneratedModuleName = $"RuntimeGeneratedModule";
    private const string CONSTANTS_RuntimeGeneratedAssemblyNameTemplate = "RuntimeGeneratedAssembly_{0}";
    private const string CONSTANTS_RuntimeGeneratedTypeNameTemplate = "RuntimeGeneratedType_{0}";

    /// <summary>Gets or sets the name of the runtime-generated module.</summary>
    /// <value>The name of the runtime-generated module.</value>
    public string RuntimeGeneratedModuleName { get; set; } = CONSTANTS_RuntimeGeneratedModuleName;

    /// <summary>Gets or sets the template to use to generate the name of runtime-generated assemblies.</summary>
    /// <value>The template to use to generate the name of runtime-generated assemblies.</value>
    /// <remarks>Should contain a "{0}" placeholder.</remarks>
    public string RuntimeGeneratedAssemblyNameTemplate { get; set; } = CONSTANTS_RuntimeGeneratedAssemblyNameTemplate;

    /// <summary>Gets or sets the template to use to generate the name of runtime-generated types.</summary>
    /// <value>The template to use to generate the name of runtime-generated types.</value>
    /// <remarks>Should contain a "{0}" placeholder.</remarks>
    public string RuntimeGeneratedTypeNameTemplate { get; set; } = CONSTANTS_RuntimeGeneratedTypeNameTemplate;
}
1赞 ggorlen 10/6/2022 #17

下面是使用 v2.0.0.61501 的完整可运行示例。csc

包:

nuget install Microsoft.AspNet.WebApi.Core
nuget install Microsoft.Net.Http
nuget install Newtonsoft.Json

法典:

using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Threading.Tasks;

public static class App
{
    static void Main()
    {
        MainAsync().GetAwaiter().GetResult();
    }

    static async Task MainAsync()
    {
        string url = "https://httpbin.org/get";
        var client = new HttpClient();

        // The verbose way:
        //HttpResponseMessage response = await client.GetAsync(url);
        //response.EnsureSuccessStatusCode();
        //string responseBody = await response.Content.ReadAsStringAsync();

        // Or:
        string responseBody = await client.GetStringAsync(url);

        var obj = JsonConvert.DeserializeObject<dynamic>(responseBody);
        Console.WriteLine(obj);
        Console.WriteLine(obj.headers.Host);
    }
}

编译器命令:

 csc http_request2.cs -r:".\Microsoft.AspNet.WebApi.Core.5.2.9\lib\net45\System.Web.Http.dll" -r:".\Microsoft.Net.Http.2.2.29\lib\net40\System.Net.Http.dll" -r:".\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll"

输出:

{
  "args": {},
  "headers": {
    "Host": "httpbin.org",
    "X-Amzn-Trace-Id": "Root=1-633dce52-64f923bb42c99bf46f78672c"
  },
  "origin": "98.51.7.199",
  "url": "https://httpbin.org/get"
}
httpbin.org

Per 无法加载文件或程序集 Newtonsoft.json。系统找不到指定的文件,我不得不将旁边移动到已编译的二进制文件旁边。Newtonsoft.Json.dll