6eccdfac489a56378f459994666ec670.jpeg

概述:介绍处理 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编程大全    

GitHub 加速计划 / js / json
41.72 K
6.61 K
下载
适用于现代 C++ 的 JSON。
最近提交(Master分支:1 个月前 )
960b763e 2 个月前
8c391e04 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐