System.Text.Json 的正确使用方法使用
概述:介绍处理 JSON 数据是许多开发人员的日常任务,因为它在现代应用程序中广泛使用。随着.NET的System.Text.Json库,使用JSON从未像现在这样高效或直接。在本指南中,我们将介绍此库的基本要素,确保您拥有轻松管理 JSON 数据的工具和知识。无论你是 JSON 的新手,还是只是想提高自己的技能,让我们深入了解一下 .NET 带来了什么!原.NET 中的 System.Text.Json 命名空间为开发人员提供了为各种 JSON 操作(无论是创建、更新、删除还是遍历)量身定制的强大类。通过对 JsonValue、JsonObject、JsonArray、JsonDocument 和
介绍
处理 JSON 数据是许多开发人员的日常任务,因为它在现代应用程序中广泛使用。随着.NET的System.Text.Json库,使用JSON从未像现在这样高效或直接。在本指南中,我们将介绍此库的基本要素,确保您拥有轻松管理 JSON 数据的工具和知识。无论你是 JSON 的新手,还是只是想提高自己的技能,让我们深入了解一下 .NET 带来了什么!
原
.NET 中的 System.Text.Json 命名空间为开发人员提供了为各种 JSON 操作(无论是创建、更新、删除还是遍历)量身定制的强大类。通过对 JsonValue、JsonObject、JsonArray、JsonDocument 和 JsonNode 的理解,在 .NET 中操作 JSON 从未像现在这样直观和高效。
JsonValue
JsonValue 表示 JSON 中的原子元素,迎合基本数据类型:数字、字符串、布尔值和 null。通过简单的实例化,您可以在 JSON 范式中封装字符串。但真正的美在于它的类型安全性。隐式转换是基石,允许以本机 .NET 格式检索值。虽然 JsonValue 在个人价值方面大放异彩,但请记住,它不是为复杂结构而设计的——这就是我们的下一个原语发挥作用的地方。
JsonValue number = JsonValue.Create(123);
JsonValue text = JsonValue.Create("Hello World");
JsonValue flag = JsonValue.Create(false);
定义
表示简单的 JSON 值:数字、字符串、布尔值或 null。
最佳实践
非常轻量级,因为它只代表单个值。
非常适合处理单个 JSON 值的方案。
在强制转换为本机 .NET 类型时确保类型安全。
陷阱
不适合表示嵌套或复杂的 JSON 结构。
过度依赖会导致代码效率低下。
性能基准
非常轻量级,因为它只代表单个值。
Json对象
想象一下,需要 JSON 中的键值对集合。这正是 JsonObject 的领域。它不仅仅是一个静态的表示;即使在创建对象之后,您也可以动态添加、删除或更改这些对。
JsonObject employee = new JsonObject
{
["firstName"] = JsonValue.Create("John"),
["lastName"] = JsonValue.Create("Doe"),
["isManager"] = JsonValue.Create(false)
};
要更新,只需重新分配一个值:
employee["isManager"] = true;
可以使用 Remove 方法删除属性:
employee.Remove("isManager");
定义
封装 JSON 对象 — 键值对。ContainsKey 和 TryGetValue 方法进一步增强了安全性,确保密钥在任何检索尝试之前存在。但是,对于纯只读任务,JsonObject 可能有点矫枉过正。
最佳实践
用于动态 JSON 创建和操作。
JsonObject 提供了 TryGetValue 等方法来安全地访问属性。
陷阱
只读任务效率低下。对于这些,请考虑 JsonDocument。
性能基准
在表示和修改对象方面效率很高,但在只读操作方面可能不如 JsonDocument 高效。
Json数组
JSON 中的列表或序列由 JsonArray 封装。可以把它想象成一个专用于JSON的动态列表,能够进行多种操作。
JsonArray colors = new JsonArray { "red", "green", "blue" };
添加和删除操作简单:
colors.Add("black");
colors.Remove("red");
定义
表示顺序 JSON 数组。但是,确保这些数组中的类型一致性至关重要。虽然它们擅长于类似列表的结构,但对于要求更高的性能方案,本机 .NET 集合可能是更好的选择。
最佳实践
当 JSON 中的主数据结构是数组时,JsonArray 是您的首选类。
对 JSON 列表很有用,可以把它想象成 JSON 的 List<string>。
陷阱
对于大型数据集,请考虑性能影响。本机数组或列表可能更有效。
性能基准
对于顺序数据访问很有效,但与本机 .NET 数组相比,随机访问的速度可能较慢。
Json文档
当涉及到在不进行更改的情况下捕获 JSON 快照时,JsonDocument 脱颖而出。它是 JSON 内容的解析只读演绎版。内存效率值得注意,因为它在租用的缓冲区内运行,从而减少了分配。
using var doc = JsonDocument.Parse("{\"country\":\"Ukraine\",\"capital\":\"Kyiv\"}");
var capital = doc.RootElement.GetProperty("capital").GetString();
定义
已分析的 JSON 文档的只读表示形式。虽然它的只读特性确保了某些任务的峰值性能,但它本质上意味着结构是不可变的。如果需要修改,可能需要探索其他基元。
最佳实践
非常适合检查或查询 JSON,无需修改。
它是只读的,针对此类方案中的性能进行了优化。
陷阱
无法修改 JSON 结构。
确保妥善处置以释放租用的缓冲区内存。
性能基准
由于其租用的缓冲区机制,只读操作的高性能。
Json节点
System.Text.Json 的抽象核心是 JsonNode,它是 JsonValue、JsonObject 和 JsonArray 等的基础。它提供了 JSON 结构中任何节点的统一表示。虽然开发人员很少直接与它交互,但了解它的基本作用可以揭示其衍生品的行为。从值到对象再到数组,每个衍生品都带来了量身定制的功能集,确保开发人员拥有适合正确工作的正确工具。
JsonNode node = new JsonObject();
node["name"] = "Doe";
要在复杂的 JSON 结构中查找特定节点或值,请执行以下操作:
if(node is JsonObject obj && obj.ContainsKey("name"))
{
Console.WriteLine($"Found name: {obj["name"\]}");
}
定义
JsonValue、JsonObject 和 JsonArray 的抽象基类。
最佳实践
提供灵活性和动态 JSON 操作功能。
根据您的特定需求使用派生类型。
陷阱
由于是抽象的,因此必须了解其派生类型以用于实际应用。
性能基准
由于它是一个基类,因此在考虑派生类型时,其性能指标将更加相关。
节点到字符串
ToString()
默认情况下,每个 .NET 对象都提供一个 ToString() 方法。但是,在 JSON 的上下文中,它具有专门的功能。
JSON 节点上的 ToString() 方法提供当前值的字符串表示形式。对于字符串和数字等基元值,输出与预期一致。但是,对于更复杂的对象,输出将被格式化以提高可读性,并具有适当的缩进和换行符。
var simpleValue = JsonValue.Create("Alice");
Console.WriteLine(simpleValue.ToString());
// Output: Alice
var complexValue = new JsonObject
{
["id"] = 1,
["name"] = "Bob",
["tags"] = new JsonArray { "friend", "developer" }
};
Console.WriteLine(complexValue.ToString());
/* Output:
{
"id": 1,
"name": "Bob",
"tags": [
"friend",
"developer"
]
}
*/
如上所述,ToString() 方法可确保缩进更复杂的对象,从而提高人类的可读性。
ToJsonString()
ToString() 的目标是可读性,而 ToJsonString() 的目标是紧凑且有效的 JSON 输出。当您正在寻找可以通过网络传输或存储在数据库中的正确 JSON 表示形式时,可以使用这种方法。
var simpleValue = JsonValue.Create("Alice");
Console.WriteLine(simpleValue.ToJsonString());
// Output: "Alice"
var complexValue = new JsonObject
{
["id"] = 1,
["name"] = "Bob",
["tags"] = new JsonArray { "friend", "developer" }
};
Console.WriteLine(complexValue.ToJsonString());
// Output: {"id":1,"name":"Bob","tags":["friend","developer"]}
请注意,在 ToJsonString() 中,字符串值用双引号括起来,与 JSON 标准一致。对于复杂对象,消除了空格和换行符以产生紧凑的表示。
定制
除了基本转换之外,ToJsonString() 还允许使用 JsonSerializerOptions 进行自定义。当您需要修改序列化输出以满足某些要求(如驼峰外壳属性)时,这很方便。
var data = new JsonObject
{
["FirstName"] = "Charlie",
["LastName"] = "Brown"
};
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};
Console.WriteLine(data.ToJsonString(options));
// Output: {"firstName":"Charlie","lastName":"Brown"}
在上面的示例中,JsonSerializerOptions 用于将属性名称更改为驼峰大小写。
技巧和窍门
System.Text.Json 已将自己确立为用于 .NET 中 JSON 操作的高性能和轻量级库。无论您是新手还是已经使用了一段时间,一些见解都可以优化您的使用并解决常见挑战。
使用属性命名策略
默认情况下,System.Text.Json 按原样使用属性名称。但通常,API 中的 JSON 属性采用蛇形大小写或其他格式。
如果要为单个属性指定不同的名称,请使用 JsonPropertyNameAttribute。
对于全局设置,请利用 PropertyNamingPolicy。例如,将 JsonSerializerOptions 与 PropertyNamingPolicy = JsonNamingPolicy.CamelCase 结合使用,以自动处理骆驼大小写 JSON 属性。
处理 Null 值
如果要从序列化中排除具有 null 值的属性,请设置 DefaultIgnoreCondition 属性:
var options = new JsonSerializerOptions
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
复杂类型的自定义转换器
有时,内置序列化可能还不够,尤其是对于复杂类型。
实现 JsonConverter<T> 以指示类型应如何序列化和反序列化。实现后,使用 JsonConverterAttribute 将其附加到类,或将其添加到 JsonSerializerOptions 中的 Converters 集合中。
选择 ReadOnlySpan<byte> 以提高性能
读取大型 JSON 有效负载时>,请使用 ReadOnlySpan<byte 或 ReadOnlyMemory<byte>而不是字符串,因为它们可以避免额外的分配,从而获得更好的性能。
将 Utf8JsonReader 用于流式处理方案
Utf8JsonReader 是一个高性能的只进读取器。它非常适合流式处理方案或读取大型数据集,确保将内存开销降至最低。
全局设置的 JsonSerializerOptions
与其每次都设置序列化选项,不如配置全局 JsonSerializerOptions 对象并重用它。这确保了一致性并减少了重复代码。
区分大小写
默认情况下,反序列化区分大小写。如果要更改此行为,请调整 JsonSerializerOptions 中的 PropertyNameCaseInsensitive 属性。
始终处置 JsonDocument
应始终释放 JsonDocument 以释放租用的内存缓冲区。一种常见的方法是使用 using 语句。
System.Text.Json 与 Newtonsoft.Json
System.Text.Json 和 Newtonsoft.Json 是两个常用的库,用于在 .NET 中处理 JSON。两者都有其优点和缺点,这使得它们或多或少适合某些场景。
起源和受欢迎程度
**Newtonsoft.Json:**它由 James Newton-King 发布,由于其丰富的功能集和灵活性,它迅速成为 .NET 中 JSON 处理的事实标准。
**System.Text.Json:**由 Microsoft 在 .NET Core 3.0 中作为内置库引入,旨在获得更好的性能并与核心框架更紧密地集成。
性能
**Newtonsoft.Json:**通常被认为比 System.Text.Json 慢,因为它提供了更广泛的功能集,从而导致一些开销。
**System.Text.Json:**从头开始为性能而设计。通常提供更高的吞吐量和更少的内存使用,尤其是在 I/O 绑定操作中。
API & 功能
**Newtonsoft.Json:**提供丰富而广泛的 API。它支持 JSONPath、JSON 中的注释、各种序列化设置以及处理复杂场景的能力等功能。
**System.Text.Json:**具有针对常见用例的更简化的 API。最初,它缺少 Newtonsoft.Json 中的一些功能,但在后续版本中已经解决了许多差距。
灵活性
**Newtonsoft.Json:**以其灵活性而闻名。提供了多种方法来调整 JSON 输出、管理序列化/反序列化和处理特殊情况。
**System.Text.Json:**在处理 JSON 以确保性能的方法上更加固执己见。然而,这有时可能意味着在边缘情况下的灵活性较低。
集成
**Newtonsoft.Json:**鉴于其悠久的历史,许多第三方库和平台都内置了对它的支持。
System.Text.Json: 作为较新的生态系统,其生态系统的整合正在增长。在 Microsoft 的推动下,越来越多的图书馆和平台开始在原生支持它。
迁移
**Newtonsoft.Json:**由于 API 和行为的差异,那些使用现有项目的人可能会发现迁移到 System.Text.Json 很麻烦。
**System.Text.Json:**虽然从 Newtonsoft.Json 转换可能会遇到挑战,但使用 System.Text.Json 启动新项目可能很简单。
目标框架
**Newtonsoft.Json:**适用于完整的 .NET Framework、.NET Core 和其他平台。
**System.Text.Json:**是 .NET Core 的本机版本,在后续版本中可用。
结论
在 System.Text.Json 和 Newtonsoft.Json 之间进行选择应基于项目的特定需求。如果性能是主要关注点,并且 System.Text.Json 的功能集满足项目的要求,则它可能是更好的选择。另一方面,需要广泛功能、广泛自定义或对 Newtonsoft.Json 具有现有依赖关系的项目可能更合适。
总结
System.Text.Json 提供了一套全面的工具,用于在 .NET 中进行 JSON 处理。通过了解每个类的细微差别和最合适的场景,开发人员可以编写高效、干净和高性能的代码来满足他们的所有 JSON 需求。
如果你喜欢我的文章,请给我一个赞!谢谢
-
技术群:添加小编微信并备注进群
小编微信:mm1552923
公众号:dotNet编程大全
更多推荐
所有评论(0)