在 C# 中交互 JSON 数据
浓缩版:请跳转至 总结
部分。
JSON 数据的准备
这里使用的 JSON 数据,必须是对象数组。该对象数组里面的元素对象要使用一样的字段,且包含至少一个唯一值字段。
比如
1 | // nodes.json |
显然,这个 JSON 数据可以视作一张数据表,每一个元素对象可以视作数据表的一条记录(行),字段可以视作表的字段(列):
id | name | coord |
---|---|---|
1 | 412总站 | [0, 0] |
2 | 融通路华翠北路口 | [-100.0, 0.0] |
3 | 海八路华翠北路口 | [-100.0, -20.0] |
JSON 数据在 C# 的加载
加载分三部走:
- 引入 Newtonsoft.Json 命名空间(来自 Newtonsoft.Json 的 NuGet包);
- 定义一个 JSON 数据类,让它的实例表示 JSON 数据的对象;
- 定义加载该 JSON 数据的方法,并把它放在
DataLoader
类。
引入 Newtonsoft.Json
命名空间
使用该 using
指令即可:
1 | using Newtonsoft.Json; |
定义 JSON 数据类
新建一个类,它的字段要包含 JSON 数据中所有的字段,并且要选择合适的字段类型.
对前面举例过的 nodes.json
数据,可以定义如下的 Node
类:
1 | public class Node |
可以看出,我们要在每个字段前面加上 [JsonProperty("<JSON字段名>")]
特性,指定 C# 字段名在 JSON 数据中的对应名称。
关于字段类型的声明:
如果是数字类型,直接用
类型名称 字段名 { get; set; }
即可。如果是字符串类型,可以用
string 字段名 { get; set; } = "";
声明,尽量避免用string?
。如果是数组或集合类型(对应 JSON 的数组类型),可以用
类型名称 字段名 { get; set; } = []
声明。
关于字段的数组或集合类型的选择:
使用数组
T[]
的情况:固定长度,所有元素同类型。使用列表
List<T>
的情况:长度不固定,所有元素同类型。
切记不要用元组!!因为 Newtonsoft.Json
暂时不支持反序列化元组类型字段。
这里可以看出要注意的地方:JSON 数组类型一定要是用同类型元素!!因为 C# 数组和列表都只支持同类型元素。
定义 JSON 数据的加载方法
加载的目的就是将 JSON 数据映射到 C# 字典(“ID: 对象”的键值对)。
于是,我们需要新建一个 DataLoader
类,里面每一个静态方法都对应着一个 JSON 转换为 C# 字典的过程。
加载 nodes.json
数据的方法可以写成:
1 | // DataLoader.cs |
此时,这个函数就会返回一个对应这个 JSON 数据的 C# 字典,可以将其赋值给某个全局变量:
1 | // class Program, Program.cs |
从方法体可看出,JsonConvert.DeserializeObject<List<JSON数据类>
可以直接把 JSON 文本映射到 C# 对象列表,其中这个 JSON数据类
在之前 定义 JSON 数据类
部分已经定义好了。然后,我们用 ToDictionary
方法把这个列表转换为字典,利于对象的索引。
JSON 数据在 C# 的访问
对前面给出的 nodes.json
访问它 id=3
的记录的 name
值,在 C# 可以表示为
1 | // a function, class Mainwindow, MainWindow.xaml.cs |
可以看出,字典对应的全局变量[ID].字段名
就可以访问到某个 JSON 对象中某个字段的值。
JSON 数据从 C# 的保存
保存的目的就是重新把 C# 字典(“ID: 对象”的键值对)映射到 JSON 数据。
于是,我们创建一个 DataSaver
类,里面每一个静态方法都对应着一个 C# 字典转换为 JSON 的过程。
保存 nodes.json
数据的方法可以写成:
1 | // DataSaver.cs |
可以看出,这个方法先把数据字典转为列表,然后通过方法 JsonConvert.SerializeObject
把列表转为 JSON 文本,并保存到文件。
需要注意的是,如果在数据类中定义了不需要导出为 JSON 的属性,需要给这些属性添加 [JsonIgnore]
特性,比如在 Node
类中,GeoCoord
字段不需要导出:
1 | // class Node, Node.cs |
总结
准备数据:[{对象1}, {对象2}, {对象3},...]
(对象共用字段且含 id
字段)。
加载数据:
定义数据类:属性前加上
[JsonProperty("<JSON字段名>")]
特性,属性如果是集合类型只能选数组或列表。定义加载方法:
- 先用
File.ReadAllText(JSON位置)
将其转为字符串 - 然后用
JsonConvert.DeserializeObject<List<数据类>>
将其转为列表 - 最后用
ToDictionary(对象 => 对象.id, 对象 => 对象)
将其转为字典。
- 先用
访问数据:字典对应的全局变量[ID].字段名
。
保存数据:
定义保存方法:
- 先用
Program.Nodes.Values.ToList()
将数据字典转为列表 - 然后用
JsonConvert.SerializeObject
将其转为 JSON 文本 - 最后用
File.WriteAllText(JSON位置, JSON文本)
保存到文件。
- 先用
注意不要导出不需要的字段要加上
[JsonIgnore]
特性。