使用 Json.net 将 JSON 对象反序列化为动态对象

Posted

技术标签:

【中文标题】使用 Json.net 将 JSON 对象反序列化为动态对象【英文标题】:Deserialize JSON object into dynamic object using Json.net 【发布时间】:2011-05-30 23:13:12 【问题描述】:

是否可以使用 json.net 从 json 反序列化返回动态对象?我想做这样的事情:

dynamic jsonResponse = JsonConvert.Deserialize(json);
Console.WriteLine(jsonResponse.message);

【问题讨论】:

考虑从 JSON json2csharp.com 生成 C# 类并使用生成的类而不是动态的 Deserialize JSON into C# dynamic object?的可能重复 你如何建议***关闭一个“太旧”的问题?已经六年了,从那时起,每个版本的 .net 都有有效的答案和合理的建议......太多以至于它们不再真正有用了。 【参考方案1】:

Json.NET 允许我们这样做:

dynamic d = JObject.Parse("number:1000, str:'string', array: [1,2,3,4,5,6]");

Console.WriteLine(d.number);
Console.WriteLine(d.str);
Console.WriteLine(d.array.Count);

输出:

 1000
 string
 6

此处的文档:LINQ to JSON with Json.NET

另见JObject.Parse和JArray.Parse

【讨论】:

请注意,数组的语法是JArray.Parse 为什么要使用动态词?我害怕以前从未使用过:D 在VB.Net中你需要做Dim d As Object = JObject.Parse("number:1000, str:'string', array: [1,2,3,4,5,6]") @MonsterMMORPG 你应该是 :) 几乎在所有情况下,动态都是一种反模式,但是,有时,你可能会遇到合理使用它的情况。 使用 Newtonsoft.Json 8.0.3 (.NET 4.5.2):发生 Microsoft.CSharp.RuntimeBinder.RuntimeBinderException HResult=-2146233088 Message='Newtonsoft.Json.Linq.JObject' 不包含'number' Source=Microsoft.CSharp StackTrace 的定义:在 Microsoft.CSharp.RuntimeBinder.RuntimeBinderController.SubmitError(CError pError)【参考方案2】:

从 Json.NET 4.0 Release 1 开始,有原生动态支持:

[Test]
public void DynamicDeserialization()

    dynamic jsonResponse = JsonConvert.DeserializeObject("\"message\":\"Hi\"");
    jsonResponse.Works = true;
    Console.WriteLine(jsonResponse.message); // Hi
    Console.WriteLine(jsonResponse.Works); // True
    Console.WriteLine(JsonConvert.SerializeObject(jsonResponse)); // "message":"Hi","Works":true
    Assert.That(jsonResponse, Is.InstanceOf<dynamic>());
    Assert.That(jsonResponse, Is.TypeOf<JObject>());

当然,获取当前版本的最佳方式是通过 NuGet。

已更新(2014 年 11 月 12 日)以解决 cmets:

这工作得很好。如果您在调试器中检查类型,您将看到该值实际上是 dynamic基础类型JObject。如果你想控制类型(比如指定ExpandoObject,那就这样做吧。

【讨论】:

这似乎永远不会起作用。它只返回一个 JObject,而不是动态变量。 顺便说一句,这有效:JsonConvert.DeserializeObject(STRING);具有适当的反序列化,所以我们没有 JObject 等。 @Gutek 不确定您的问题是什么。你运行代码了吗?我在测试中添加了断言,并添加了一个不在原始 json 中的属性。包含调试器的屏幕截图。 @DavidPeden 如果你有 JObject 并且你会尝试在 Razor 中绑定它,你会得到异常。问题是关于反序列化为动态对象 - JObject 是动态的,但包含“自己的”类型,如 JValue 而不是原始类型。如果返回类型是 JValue,我不能在 Razor 中使用 @Model.Prop 名称。 这可行,但每个动态属性都是JValue。这让我很困惑,因为我在调试器/即时窗口中工作,而不仅仅是看到strings。大卫在底部的屏幕截图中展示了这一点。 JValue 是可转换的,所以你可以做 string m = jsonResponse.message【参考方案3】:

如果你只是反序列化为动态,你会得到一个 JObject。您可以使用 ExpandoObject 获得您想要的。

var converter = new ExpandoObjectConverter();    
dynamic message = JsonConvert.DeserializeObject<ExpandoObject>(jsonString, converter);

【讨论】:

结果也可以转成字典 正是我想要的!谢谢!【参考方案4】:

我知道这是旧帖子,但 JsonConvert 实际上有一个不同的方法,所以它会是

var product = new  Name = "", Price = 0 ;
var jsonResponse = JsonConvert.DeserializeAnonymousType(json, product);

【讨论】:

这会将 json 有效负载反序列化为匿名类型,而不是动态类型。匿名类型和动态类型是不同的东西,我认为这不能解决所提出的问题。 有必要使用两个变量吗?为什么不在第二个语句中重用第一个?【参考方案5】:

是的,您可以使用 JsonConvert.DeserializeObject 来实现。为此,只需执行以下操作:

dynamic jsonResponse = JsonConvert.DeserializeObject(json);
Console.WriteLine(jsonResponse["message"]);

【讨论】:

JsonConvert 不包含名为 Deserialize 的方法。 它应该只是 DeserializeObject,但这应该是 IMO 接受的答案 这行得通:D 非常感谢,所有其他答案都对我不起作用。我试图使用 DeserializeObject,但是我使用的是通常用于常规类对象的语法,而不是 jsonResponse["message"]:jsonResponse.message【参考方案6】:

注意:当我在 2010 年回答这个问题时,没有某种类型就无法反序列化,这使您无需去定义实际类就可以反序列化并允许匿名用于进行反序列化的类。


你需要有某种类型来反序列化。您可以按照以下方式做一些事情:

var product = new  Name = "", Price = 0 ;
dynamic jsonResponse = JsonConvert.Deserialize(json, product.GetType());

我的答案基于 .NET 4.0 内置 JSON 序列化程序的解决方案。反序列化为匿名类型的链接在这里:

http://blogs.msdn.com/b/alexghi/archive/2008/12/22/using-anonymous-types-to-deserialize-json-data.aspx

【讨论】:

我和你在一起菲尔不知道为什么人们不赞成这个,如果有人可以请你..请解释为什么? 他们投反对票是因为问题是关于没有类型的反序列化。 答案在 2010 年编写时有效,当时没有其他解决方案。在 JSON.NET 得到支持之前,它甚至在很短的一段时间内都是公认的答案。 这不会产生动态对象。这会生成一个 JObject,您将其作为动态引用。但它仍然是一个 JObject 里面。 @ghostbust555 所以,和dynamic d = JObject.Parse...没有什么不同【参考方案7】:

如果您将 JSON.NET 与没有 JObject 的旧版本一起使用。

这是从 JSON 创建动态对象的另一种简单方法: https://github.com/chsword/jdynamic

NuGet 安装

PM> Install-Package JDynamic

支持使用字符串索引访问成员like:

dynamic json = new JDynamic("a:a:1");
Assert.AreEqual(1, json["a"]["a"]);

测试用例

你可以使用这个工具如下:

直接获取值

dynamic json = new JDynamic("1");

//json.Value

2.获取json对象中的成员

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 integer: 1

3.IEnumerable

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.

其他

dynamic json = new JDynamic("a:a:1 ");

//json.a.a is 1.

【讨论】:

这很好。我一直在寻找这样的东西....正好填写了简介【参考方案8】:

是的,这是可能的。我一直都在这样做。

dynamic Obj = JsonConvert.DeserializeObject(<your json string>);

对于非原生类型来说有点棘手。假设在您的 Obj 内部,有一个 ClassA 和 ClassB 对象。它们都被转换为 JObject。你需要做的是:

ClassA ObjA = Obj.ObjA.ToObject<ClassA>();
ClassB ObjB = Obj.ObjB.ToObject<ClassB>();

【讨论】:

【参考方案9】:

如果有人试图将 JSON 反序列化为匿名对象,您可以使用 NewtonSoft.Json 的 DeserializeAnonymousType 方法来实现。

以下示例甚至可以将 JSON 反序列化为匿名对象的列表

var json = System.IO.File.ReadAllText(@"C:\TestJSONFiles\yourJSONFile.json");
var fooDefinition = new  a = "", b = 0 ; // type with fields of string, int
var fooListDefinition = Enumerable.Range(0, 0).Select(e => fooDefinition).ToList();

var foos = JsonConvert.DeserializeAnonymousType(json, fooListDefinition);

【讨论】:

以上是关于使用 Json.net 将 JSON 对象反序列化为动态对象的主要内容,如果未能解决你的问题,请参考以下文章

Json.NET:将嵌套数组反序列化为强类型对象

.NET Core - Json.NET反序列化映射

Json.NET:反序列化嵌套字典

JSON.net 反序列化对象嵌套数据

使用Newtonsoft.Json.dll(JSON.NET)动态解析JSON.net 的json的序列化与反序列化

使用 Json.net 反序列化 JSON 对象数组