我想对其他答案进行一些扩展,并对主题进行更多说明。
JSON - JavaScript 对象 Notation - 只是一种“在线”移动数据的方式。在 .NET 中,您不应该真正将您的对象视为 JSON,尽管您可以通俗地指代这样的数据结构。
话虽如此,.NET“内部”的 JSON 是什么?这是你的电话。例如,您可以将其视为string,但您将很难根据某些参数/规则执行此查找特定节点的操作。
由于 JSON 是一种树状结构,您可以构建自己的数据结构或使用网络上的许多可用数据结构。如果您正在学习语言的工作原理和一般的编程,这很好,如果您专业地这样做,那就不好了,因为您可能会重新发明轮子。并且解析 JSON 并不是一件容易的事(同样,很好的练习)。
那么,最省时的做法是什么?你有两个选择:
使用 dynamic 对象来表示您的 JSON 数据。动态是 .NET 的“扩展”(实际上是 CLR 的扩展,称为 DLR),它允许您创建没有类的对象(它们可以被认为是“无类型的”,或者更好的是,使用 duck 打字)。
使用您定义的类型化结构来保存数据。这是规范的、面向对象的 .NET 方式,但在声明类和键入所有内容方面存在折衷,这在时间方面是昂贵的。回报是您可以获得更好的智能感知、性能(DLR 对象比传统对象慢)和更安全的代码。
要采用第一种方法,您可以参考@YouneS 的答案。您需要在项目中添加一个依赖项 Newtonsoft.Json(一个 nuget),并调用反序列化将 JSON 字符串转换为动态对象。正如您从他的回答中看到的那样,您可以像访问 JavaScript 语言一样访问此对象中的属性。但是您也会意识到您没有智能感知,并且将允许使用诸如 myObj.unexistentField = "asd" 之类的内容。这就是动态类型对象的本质。
第二种方法是声明所有类型。同样,这很耗时,而且在许多情况下,您宁愿不这样做。请参阅Microsoft Docs 了解更多信息。
您应该首先创建您的数据合同,如下所示(请原谅我的任何拼写错误,我没有编译代码)。
[DataContract]
class DataItem
{
[DataMember]
public string Start { get; set; }
[DataMember]
public string[] Subjects { get; set; }
}
[DataContract]
class ResponseItem
{
[DataMember]
public DateItem[] Data { get; set; }
}
[DataContract]
class ResponseContract
{
[DataMember]
public ResponseItem Response { get; set; }
}
一旦你声明了所有这些数据结构,将你的 json 反序列化为它:
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
var deserializer = new DataContractJsonSerializer(typeof(ResponseContract));
return (T)deserializer.ReadObject(ms);
}
上面的代码可能看起来有点复杂,但遵循一点 .NET / BCL 标准。 DataContractJsonSerializer 仅适用于流,因此您需要打开一个包含您的字符串的流。因此,您使用 json 字符串中的所有字节创建了一个内存流。
您也可以使用 Newtonsoft 来执行此操作,这要简单得多,但当然仍然需要额外的依赖:
DataContract contract = JsonConvert.DeserializeObject<DataContract>(output);
如果您使用这种方法,您就不需要在您的类上添加注释(所有这些 DataMember 和 DataContract),从而使代码更加简洁。我非常喜欢使用这种方法而不是 DataContractJsonSerializer,但这是你的决定。
我已经谈了很多关于序列化和反序列化对象的问题,但您的问题是,“我如何找到某个节点?”。上面的所有讨论只是一个先决条件。
和往常一样,有几种方法可以实现您想要的:
@YouneS 回答。它非常简单,可以满足您的需求。
-
使用上面的第二种方法,然后使用您的类型对象来获得您想要的。例如:
var contract = JsonConvert.DeserializeObject<DataContract>(output);
var query = from dataItem in contract.Response.Data
where dataItem.Start > 1.3
order by dataItem.Start;
var item = query.FirstOrNull();
这将返回第一个项目,因为它是有序的,应该是最小的。记得测试结果是否为 null。
- 您可以使用 Newtonsoft 的一项功能,直接找到您想要的节点。请参阅the documentation。警告,对于简单的情况,它有点高级,可能有点矫枉过正。