1. 回顾 JSON
JSON 的全称是 JavaScript Object Notation。虽然名字里有让人紧张的 JavaScript,但这个格式本质上与语言无关,对几乎所有(嗯,差不多所有)编程语言都很友好,包括 C#。它的设计目的就是用普通文本方便、清楚地描述数据 —— 对象、数组、列表和字典。
在现代世界里,几乎每个程序都需要和别的程序交流,JSON 已经基本成为序列化和交换结构化数据的事实标准。它随处可见:从 REST API 到保存用户设置,甚至服务间内部通信。理由很简单 —— 人能读得懂(前提是不怕大括号),解析也容易,且被所有现代语言和库支持。
为什么不用 XML?
JSON 比 XML 更简单、更短,也更容易阅读。而且没有多余的噪音和标签,更贴合大多数编程语言的数据结构。也不用折腾闭合标签、引号和其他 XML 的繁琐。总之 —— JSON 就是 更快、更简单、更方便。
2. JSON 语法的基本要素
可以把 JSON 想成一棵简单的树(或者套娃),由对象、数组和基本数据组成。我们手头有这些「积木」:
对象 (Objects)
JSON 对象 是一组 «键: 值» 对,包在花括号里 { }。
示例:
{
"name": "Alice",
"age": 23
}
在 C# 中,这样的结构可以表示为类或字典。
数组 (Arrays)
JSON 数组 是一个有序的元素列表(元素可以是任意类型),用方括号包起来 [ ]。
示例:
[1, 2, 3, 42]
或者:
[
{"name": "Ivan"},
{"name": "Olga"}
]
在 C# 中对应 List<T>、T[] 等集合。
键-值对
键总是 字符串(必须用双引号!),值可以是 JSON 允许的任意数据类型。
示例:
{
"id": 123,
"login": "student",
"isActive": true
}
JSON 中的数据类型
| JSON 类型 | 示例 | 说明 |
|---|---|---|
| 数字 (Number) | |
整数或小数 |
| 字符串 (String) | |
总是用双引号 |
| 布尔 (Boolean) | |
布尔值 |
| null | |
表示没有值 |
| 对象 (Object) | |
字典或带字段的实体 |
| 数组 (Array) | |
值的序列 |
示例 — 综合演示:
{
"id": 1,
"name": "Bob",
"scores": [10, 20, 30],
"profile": {
"email": "bob@mail.com",
"phone": null
},
"isAdmin": false
}
看,多紧凑也多清晰地描述了一个用户对象。
3. JSON 的书写规则
字符串必须用双引号
即便很想用单引号,JSON 也不允许。正确写法:
{ "name": "Vera" }
下面这样是 错误 的:
{ 'name': 'Vera' }
键 —— 只能是字符串
和 C# 不同(在 C# 中字典的键可以是 int 或 enum),在 JSON 里键永远是字符串:
{ "2025": "C# 年", "favorite": true }
不要尾随逗号
和 C# 的数组或对象不同,JSON 在闭括号前出现多余的逗号会导致语法错误!
// 错误!(最后一个逗号不允许)
{
"id": 10,
"name": "Oleg",
}
正确:
{
"id": 10,
"name": "Oleg"
}
空格和换行
可以为了美观加上空格和换行,解析器会忽略它们。通常对“面向人”的格式使用 pretty-printed(可读的格式化)JSON,网络传输时使用 minified(压缩成一行、无空格)。
4. C# 对象如何被转换为 JSON
如果你用 System.Text.Json.JsonSerializer.Serialize() 来序列化对象,那么对象的字段和属性会变成「键-值」对。
C# 类和序列化示例
public class Book
{
public string Title { get; set; }
public int Pages { get; set; }
}
var book = new Book { Title = "CLR via C#", Pages = 900 };
string json = JsonSerializer.Serialize(book);
Console.WriteLine(json); // {"Title":"CLR via C#","Pages":900}
集合
- List<int> 会变成 [1,2,3]
- string[] 会变成 ["hi", "wow"]
- List<Person> — 变成对象数组
字典
像 Dictionary<string, int> 这样的字典会变成一个对象:
var dict = new Dictionary<string, int>
{
["apples"] = 5, ["bananas"] = 10
};
string json = JsonSerializer.Serialize(dict);
// {"apples":5,"bananas":10}
5. 可视化示意:JSON 如何构建
嵌套 —— 像套娃
对象
│
├── 键值对: "name": "Alex"
├── 键值对: "hobbies": 数组
│ │
│ ├── "skiing"
│ └── "programming"
└── 键值对: "profile": 对象
│
├── "age": 42
└── "city": "巴塞尔"
结果:
{
"name": "Alex",
"hobbies": ["skiing", "programming"],
"profile": {
"age": 42,
"city": "巴塞尔"
}
}
6. 常见错误与语法注意事项
编程世界没有完美——JSON 也有坑!如果你发送的 JSON 引号不对、多了逗号或键没用引号包起来,解析器会报错。
还有一个坑 —— 带前导零的数字。在 JSON 中这是不允许的(例如 0123 是错误)。
值得知道: 有些解析器(比如 JavaScript 的 JSON.parse)比较宽松,能“容忍”一些小错误。但大多数严格的解析器(比如 C# / .NET 的实现)会对任何语法违规报错。
7. C# 数据转 JSON 的例子
我们来实际序列化一个稍复杂的结构。假设我们的教学应用进步了:现在有学生列表,想把它们保存成 JSON 文件。
定义类:
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
}
填充列表:
var students = new List<Student>
{
new Student { Name = "安娜", Age = 20 },
new Student { Name = "尼基塔", Age = 22 }
};
序列化:
using System.Text.Json;
// 将学生列表序列化成 JSON 字符串
string json = JsonSerializer.Serialize(students, new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(json);
/*
[
{
"Name": "安娜",
"Age": 20
},
{
"Name": "尼基塔",
"Age": 22
}
]
*/
看,多方便?每个学生都是 JSON 数组里的一个独立对象。
8. 小型生成器:如何手工写 JSON
有时候需要手工写 JSON,比如手动创建测试数据。下面是检查清单:
- 外层用花括号表示对象,外层方括号表示数组。
- 键必须是双引号包裹的字符串。
- 值可以是字符串(双引号)、数字、true、false、null、对象({})或数组([])。
- 元素之间用逗号分隔,但最后一个元素后不要逗号!
- 可以用缩进和空格提高可读性(但不是必须的)。
GO TO FULL VERSION