C# JSON
最后修改于 2025 年 5 月 13 日
本 C# JSON 教程演示了如何使用标准库的内置类来处理 JSON 数据。 JSON 是一种广泛使用的数据格式,用于在应用程序之间交换信息,尤其是在 Web 开发和 API 中。 了解如何在 C# 中解析、序列化和操作 JSON 对于构建与外部数据源或服务交互的现代 .NET 应用程序至关重要。
JSON
JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式。 它易于人类阅读和编写,同时可以被机器高效地解析和生成。 JSON 的官方 Internet 媒体类型是 application/json,JSON 文件通常使用 .json 扩展名。 JSON 支持基本数据类型,例如字符串、数字、布尔值、数组和对象,使其能够灵活地表示复杂的数据结构。
在本教程中,我们将重点介绍如何使用 C# 标准库处理 JSON。 此外,还有一个广泛使用的第三方库,名为 Json.NET,它为 JSON 处理提供了扩展的功能。 虽然出于性能和与 .NET 集成的考虑,建议大多数新项目使用 System.Text.Json,但 Json.NET 仍然因其高级功能和兼容性而广受欢迎。
System.Text.Json
System.Text.Json 命名空间为在 C# 中处理 JSON 提供了高性能、内存效率高且符合标准的解决方案。 它支持将对象序列化为 JSON 文本,以及将 JSON 文本反序列化为对象,并内置 UTF-8 优化以加快处理速度。 此命名空间包含在 .NET Core 3.0 及更高版本中,是现代 C# 应用程序中处理 JSON 的首选方式。
C# JSON 解析
JsonDocument.Parse 方法将流或字符串解析为 UTF-8 编码的数据,表示单个 JSON 值到 JsonDocument 中。 该流将被读取完毕,并且生成后的文档提供了一个类似 DOM 的 API,用于从 JSON 结构中导航和提取数据。 当您需要检查或操作 JSON 数据而无需将其直接映射到 C# 类型时,这非常有用。
using System.Text.Json;
string data = @" [ {""name"": ""John Doe"", ""occupation"": ""gardener""},
{""name"": ""Peter Novak"", ""occupation"": ""driver""} ]";
using JsonDocument doc = JsonDocument.Parse(data);
JsonElement root = doc.RootElement;
Console.WriteLine(root);
var u1 = root[0];
var u2 = root[1];
Console.WriteLine(u1);
Console.WriteLine(u2);
Console.WriteLine(u1.GetProperty("name"));
Console.WriteLine(u1.GetProperty("occupation"));
Console.WriteLine(u2.GetProperty("name"));
Console.WriteLine(u2.GetProperty("occupation"));
在此示例中,我们解析一个简单的 JSON 字符串,其中包含一个对象数组。 每个对象代表一个具有名称和职业的用户。 我们使用 JsonDocument 解析字符串并访问根元素,该根元素是一个数组。 然后,我们使用提供的 API 提取单个元素及其属性。 这种方法在处理动态或未知的 JSON 结构时很有用。
using JsonDocument doc = JsonDocument.Parse(data);
我们将 JSON 字符串解析为 JsonDocument,这使我们可以使用类似 DOM 的 API 导航 JSON 结构。 当 JSON 的结构在编译时未知或者您只需要访问数据的一个子集时,这尤其有用。
JsonElement root = doc.RootElement;
我们使用 RootElement 属性获取对根元素的引用。 根元素可以是对象、数组或原始值,具体取决于 JSON 数据。
var u1 = root[0]; var u2 = root[1]; Console.WriteLine(u1); Console.WriteLine(u2);
使用 [] 运算符,我们获得 JSON 文档的第一个和第二个子元素。 这使我们可以访问数组中的单个对象,并进一步检查它们的属性。
Console.WriteLine(u1.GetProperty("name"));
Console.WriteLine(u1.GetProperty("occupation"));
我们使用 GetProperty 获取元素的属性。 此方法从 JSON 对象中检索指定名称的属性值,使我们能够从数据中提取特定字段。
$ dotnet run
[ {"name": "John Doe", "occupation": "gardener"},
{"name": "Peter Novak", "occupation": "driver"} ]
{"name": "John Doe", "occupation": "gardener"}
{"name": "Peter Novak", "occupation": "driver"}
John Doe
gardener
Peter Novak
driver
C# JSON 枚举
在此示例中,我们枚举根元素的内容,该根元素是一个 JSON 数组。 我们使用 EnumerateArray 方法迭代数组中的每个对象,然后使用 EnumerateObject 访问每个对象的所有属性。 这种方法对于处理 JSON 格式的数据集合(例如用户或项目列表)非常有用。
using System.Text.Json;
string data = @" [ {""name"": ""John Doe"", ""occupation"": ""gardener""},
{""name"": ""Peter Novak"", ""occupation"": ""driver""} ]";
using var doc = JsonDocument.Parse(data);
JsonElement root = doc.RootElement;
var users = root.EnumerateArray();
while (users.MoveNext())
{
var user = users.Current;
System.Console.WriteLine(user);
var props = user.EnumerateObject();
while (props.MoveNext())
{
var prop = props.Current;
Console.WriteLine($"{prop.Name}: {prop.Value}");
}
}
我们使用 EnumerateArray 获取子元素的数组。 此方法返回一个枚举器,该枚举器允许我们循环遍历 JSON 数组中的每个元素,从而可以轻松地处理多个项目。
var users = root.EnumerateArray();
在 while 循环中,我们遍历元素数组。 对于每个元素,我们打印整个对象,然后枚举其属性。 这演示了如何遍历嵌套的 JSON 结构并从每个对象中提取详细信息。
while (users.MoveNext())
{
var user = users.Current;
Console.WriteLine(user);
...
在第二个 while 循环中,我们遍历每个元素的属性。 我们使用 EnumerateObject 访问 JSON 对象中的所有键值对,从而可以单独打印或处理每个属性。
var props = user.EnumerateObject();
while (props.MoveNext())
{
var prop = props.Current;
Console.WriteLine($"{prop.Name}: {prop.Value}");
}
$ dotnet run
{"name": "John Doe", "occupation": "gardener"}
name: John Doe
occupation: gardener
{"name": "Peter Novak", "occupation": "driver"}
name: Peter Novak
occupation: driver
C# JSON 序列化
在此示例中,我们使用 JsonSerializer.Serialize 将 User 对象转换为 JSON 字符串。 序列化是将对象或数据结构转换为可以轻松存储或传输的格式(例如 JSON)的过程。 这通常用于将数据发送到 Web API 或保存配置文件。
using System.Text.Json;
var user = new User("John Doe", "gardener", new MyDate(1995, 11, 30));
var json = JsonSerializer.Serialize(user);
Console.WriteLine(json);
record MyDate(int year, int month, int day);
record User(string Name, string Occupation, MyDate DateOfBirth);
$ dotnet run
{"Name":"John Doe","Occupation":"gardener",
"DateOfBirth":{"year":1995,"month":11,"day":30}}
C# JSON 反序列化
JsonSerializer.Deserialize 方法将表示单个 JSON 值的文本解析为指定类型的实例。 这使您可以将从外部源接收的 JSON 数据转换为强类型的 C# 对象,从而更容易在应用程序中使用数据。
using System.Text.Json;
string json = @"{""Name"":""John Doe"", ""Occupation"":""gardener"",
""DateOfBirth"":{""year"":1995,""month"":11,""day"":30}}";
var user = JsonSerializer.Deserialize<User>(json);
Console.WriteLine(user);
Console.WriteLine(user?.Name);
Console.WriteLine(user?.Occupation);
Console.WriteLine(user?.DateOfBirth);
record MyDate(int year, int month, int day);
record User(string Name, string Occupation, MyDate DateOfBirth);
该示例将 JSON 字符串解析为 User 类型的实例。 反序列化后,您可以像使用任何 C# 类一样访问对象的属性,从而可以对数据进行类型安全的处理。
C# JsonSerializerOptions
使用 JsonSerializerOptions,我们可以使用一些选项控制序列化过程。 例如,WriteIndented 选项启用美化打印,使输出更具可读性。 其他选项允许自定义属性命名、处理空值等。
using System.Text.Json;
var words = new Dictionary<int, string>
{
{1, "sky"},
{2, "cup"},
{3, "odd"},
{4, "cloud"},
{5, "forest"},
{6, "warm"},
};
var r = JsonSerializer.Serialize(words,
new JsonSerializerOptions { WriteIndented = true });
Console.WriteLine(r);
Console.WriteLine("---------------------");
var d = JsonSerializer.Deserialize<Dictionary<int, string>>(r);
foreach (var (k, v) in d!)
{
Console.WriteLine($"{k}: {v}");
}
设置 WriteIndented 选项后,我们启用缩进进行美化打印。 这对于调试或当 JSON 输出需要人为可读时非常有用,例如在配置文件或日志中。
$ dotnet run
{
"1": "sky",
"2": "cup",
"3": "odd",
"4": "cloud",
"5": "forest",
"6": "warm"
}
---------------------
1: sky
2: cup
3: odd
4: cloud
5: forest
6: warm
C# Utf8JsonWriter
在此示例中,我们创建一个新对象,并使用 Utf8JsonWriter 将其写入 JSON 字符串。 此类提供了一种高性能、仅向前 API,用于编写 UTF-8 编码的 JSON 文本。 它适用于需要动态生成 JSON 或需要对输出进行细粒度控制的场景。
using System.Text.Json;
using System.Text;
using var ms = new MemoryStream();
using var writer = new Utf8JsonWriter(ms);
writer.WriteStartObject();
writer.WriteString("name", "John Doe");
writer.WriteString("occupation", "gardener");
writer.WriteNumber("age", 34);
writer.WriteEndObject();
writer.Flush();
string json = Encoding.UTF8.GetString(ms.ToArray());
Console.WriteLine(json);
$ dotnet run
{"name":"John Doe","occupation":"gardener","age":34}
在此示例中,我们将 JSON 字符串写入文件。 使用 JsonWriterOptions 的 Indented 选项美化数据。 美化打印使 JSON 更易于阅读和维护,尤其适用于配置文件或用于手动检查的数据。
using System.Text.Json;
string data = @" [ {""name"": ""John Doe"", ""occupation"": ""gardener""},
{""name"": ""Peter Novak"", ""occupation"": ""driver""} ]";
JsonDocument jdoc = JsonDocument.Parse(data);
var fileName = @"data.json";
using FileStream fs = File.OpenWrite(fileName);
using var writer = new Utf8JsonWriter(fs, new JsonWriterOptions { Indented = true });
jdoc.WriteTo(writer);
$ cat data.json
[
{
"name": "John Doe",
"occupation": "gardener"
},
{
"name": "Peter Novak",
"occupation": "driver"
}
]
C# JSON Utf8JsonReader
在此示例中,我们使用 Utf8JsonReader 从文件中读取 JSON 数据。 它提供了一个低级别的 API,用于逐个令牌地读取 JSON 数据。 这对于高效处理大型 JSON 文件或流非常有用,因为它避免了将整个文档加载到内存中。
using System.Text.Json;
var fileName = @"/home/user7/data.json";
byte[] data = File.ReadAllBytes(fileName);
Utf8JsonReader reader = new Utf8JsonReader(data);
while (reader.Read())
{
switch (reader.TokenType)
{
case JsonTokenType.StartObject:
Console.WriteLine("-------------");
break;
case JsonTokenType.EndObject:
break;
case JsonTokenType.StartArray:
case JsonTokenType.EndArray:
break;
case JsonTokenType.PropertyName:
Console.Write($"{reader.GetString()}: ");
break;
case JsonTokenType.String:
Console.WriteLine(reader.GetString());
break;
default:
throw new ArgumentException();
}
}
$ dotnet run ------------- name: John Doe occupation: gardener ------------- name: Peter Novak occupation: driver
C# JSON 异步解析
该示例读取 .NET Core 框架的所有版本,这些版本以 JSON 字符串的形式在项目 Github 存储库上提供。 它演示了如何使用 JsonDocument.ParseAsync 从流中异步读取和解析 JSON 数据,这对于处理网络或文件 I/O 的响应式应用程序非常重要。
using System.Text.Json;
using var httpClient = new HttpClient();
var url = "https://raw.githubusercontent.com/dotnet/core/master/release-notes/releases-index.json";
var ts = await httpClient.GetStreamAsync(url);
using var resp = await JsonDocument.ParseAsync(ts);
var root = resp.RootElement.GetProperty("releases-index");
var elems = root.EnumerateArray();
while (elems.MoveNext())
{
var node = elems.Current;
Console.WriteLine(node);
}
C# HttpClient GetFromJsonAsync
GetFromJsonAsync 方法将 GET 请求发送到指定的 URL,并返回异步操作中反序列化为 JSON 的响应正文所产生的值。 此方法简化了从 Web API 获取和解析 JSON 数据的过程,从而可以轻松地将外部数据源集成到 C# 应用程序中。
该方法是 System.Net.Http.Json 中的扩展方法。
using System.Text.Json.Serialization;
using System.Net.Http.Json;
using var client = new HttpClient();
var url = "http://webcode.me/users.json";
var data = await client.GetFromJsonAsync<Users>(url);
if (data != null)
{
foreach (var user in data.users)
{
Console.WriteLine(user);
}
}
class Users
{
public List<User> users { get; set; } = new();
}
class User
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("first_name")]
public string FirstName { get; set; } = string.Empty;
[JsonPropertyName("last_name")]
public string LastName { get; set; } = string.Empty;
[JsonPropertyName("email")]
public string Email { get; set; } = string.Empty;
public override string ToString()
{
return $"User {{ {Id}| {FirstName} {LastName}| {Email} }}";
}
}
我们创建一个对 JSON 资源的异步 http 请求。 JSON 数据被序列化为 User 对象列表,从而可以轻松地在 C# 中迭代和处理数据。
var data = await client.GetFromJsonAsync<Users>(url);
GetFromJsonAsync 是一种方便的方法,可将 JSON 资源转换为 C# 集合。 它处理 HTTP 请求、响应、反序列化和错误处理,从而减少了样板代码并提高了工作效率。
class Users
{
public List<User> users { get; set; } = new();
}
我们需要为 List 集合创建一个特定的类。 此类充当反序列化数据的容器,与 JSON 响应的结构相匹配。
class User
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("first_name")]
public string FirstName { get; set; } = string.Empty;
[JsonPropertyName("last_name")]
public string LastName { get; set; } = string.Empty;
[JsonPropertyName("email")]
public string Email { get; set; } = string.Empty;
public override string ToString()
{
return $"User {{ {Id}| {FirstName} {LastName}| {Email} }}";
}
}
JSON 字段使用 JsonPropertyName 属性映射到类属性。 这确保了 C# 属性对应于正确的 JSON 字段,即使名称不同也是如此。 重写 ToString() 提供了一种显示对象数据的便捷方法。
$ dotnet run
User { 1| Robert Schwartz| rob23@gmail.com }
User { 2| Lucy Ballmer| lucyb56@gmail.com }
User { 3| Anna Smith| annasmith23@gmail.com }
User { 4| Robert Brown| bobbrown432@yahoo.com }
User { 5| Roger Bacon| rogerbacon12@yahoo.com }
来源
在本文中,我们使用了 C# 中的 JSON 数据。
作者
列出所有 C# 教程。