在 C# .NET 中驾驭 JSON:使用 Newtonsoft.Json 进行解析与 POST 请求实战

JSON (JavaScript Object Notation) 已经成为现代 Web 应用和服务之间数据交换的通用语言。无论你是开发后端 API、与第三方服务集成,还是处理配置文件,都绕不开 JSON 的解析与生成。在 C# .NET 世界里,处理 JSON 有多种选择,其中 Newtonsoft.Json(又称 Json.NET)因其强大的功能、灵活性和广泛的应用,至今仍是许多开发者的首选。

本文将深入探讨如何使用 Newtonsoft.Json 在 C# 中解析 JSON 字符串,以及如何利用 HttpClient 结合 Newtonsoft.Json 发送带有 application/json 请求体的 POST 请求。

准备工作:安装 Newtonsoft.Json

首先,确保你的项目中已经安装了 Newtonsoft.Json NuGet 包。在 Visual Studio 中,可以通过以下步骤安装:

  1. 右键点击项目,选择 “管理 NuGet 程序包…”。
  2. 在 “浏览” 标签页搜索 “Newtonsoft.Json”。
  3. 选择找到的包,点击 “安装”。

或者,在 NuGet 包管理器控制台运行以下命令:

Install-Package Newtonsoft.Json

第一部分:JSON 解析的艺术 - 将 JSON 转化为 C# 对象

处理 JSON 字符串最常见也最安全的方式是将其映射到预先定义的 C# 类或结构体。Newtonsoft.Json 提供了强大的反序列化功能,能够将 JSON 结构自动转化为对应的 C# 对象。

1. 将 JSON 反序列化为强类型对象 (JsonConvert.DeserializeObject<T>)

这种方法适用于你知道 JSON 的具体结构,并可以为其定义一个匹配的 C# 类。这是推荐的方式,因为它提供了编译时类型检查,减少了运行时错误。

假设我们有以下 JSON 数据,代表一个用户的信息:

{"userName": "Alice","age": 30,"isActive": true,"roles": ["Viewer", "Contributor"],"profile": {"email": "alice@example.com","bio": "Software Engineer"}
}

为了解析它,我们需要定义对应的 C# 类:

using System.Collections.Generic; // 用于 List<string>public class UserProfile
{public string Email { get; set; }public string Bio { get; set; }
}public class User
{// 默认情况下,属性名需要与 JSON key 匹配(大小写敏感)public string UserName { get; set; }public int Age { get; set; }public bool IsActive { get; set; }public List<string> Roles { get; set; } // JSON 数组通常映射到 List<T> 或 T[]public UserProfile Profile { get; set; } // 嵌套对象映射到嵌套类
}

然后,使用 JsonConvert.DeserializeObject<T> 方法进行反序列化:

using System;
using Newtonsoft.Json; // 引入 Newtonsoft.Json 命名空间public class JsonParsingExample
{public static void Main(string[] args){string jsonString = @"{""userName"": ""Alice"",""age"": 30,""isActive"": true,""roles"": [""Viewer"", ""Contributor""],""profile"": {""email"": ""alice@example.com"",""bio"": ""Software Engineer""}}";try{// 反序列化 JSON 字符串到 User 对象User user = JsonConvert.DeserializeObject<User>(jsonString);// 访问反序列化后的对象属性Console.WriteLine($"User Name: {user.UserName}");Console.WriteLine($"Age: {user.Age}");Console.WriteLine($"Is Active: {user.IsActive}");Console.WriteLine($"Roles: {string.Join(", ", user.Roles)}"); // 遍历列表Console.WriteLine($"Email: {user.Profile.Email}"); // 访问嵌套对象属性Console.WriteLine($"Bio: {user.Profile.Bio}");}catch (JsonReaderException ex){// 处理 JSON 格式错误或其他解析异常Console.WriteLine($"JSON 解析错误: {ex.Message}");}catch (Exception ex){// 处理其他潜在异常Console.WriteLine($"发生错误: {ex.Message}");}}
}

处理 JSON 数组:

如果你的 JSON 根是一个数组,例如 [ {"id": 1, "name": "Item A"}, {"id": 2, "name": "Item B"} ],你可以反序列化到一个 List<T>T[]

using System.Collections.Generic;public class Item
{public int Id { get; set; }public string Name { get; set; }
}string jsonArrayString = @"
[{ ""id"": 1, ""name"": ""Item A"" },{ ""id"": 2, ""name"": ""Item B"" }
]";List<Item> items = JsonConvert.DeserializeObject<List<Item>>(jsonArrayString);
// 现在 items 是一个包含两个 Item 对象的列表

自定义属性名映射 ([JsonProperty] 属性):

如果你的 C# 属性名与 JSON key 不一致(例如,C# 使用 PascalCase,JSON 使用 camelCase 或 snake_case),可以使用 [JsonProperty("json_key_name")] 属性来指定映射关系:

using Newtonsoft.Json;public class Product
{[JsonProperty("product_code")] // JSON 中是 "product_code"public string Code { get; set; } // C# 中是 Code[JsonProperty("itemPrice")] // JSON 中是 "itemPrice"public decimal Price { get; set; } // C# 中是 Price
}
2. 使用 JToken/JObject/JArray 进行动态解析

当你面对结构未知、不规范的 JSON,或者只需要访问/修改 JSON 中的一小部分数据时,将整个 JSON 强制映射到强类型对象可能不太方便。这时,Newtonsoft.Json.Linq 命名空间下的 JTokenJObjectJArray 类提供了灵活的动态访问能力。

  • JToken: 所有 JSON 元素的基类。
  • JObject: 代表一个 JSON 对象 {}
  • JArray: 代表一个 JSON 数组 []
  • JValue: 代表一个具体的 JSON 值(字符串、数字、布尔、null)。

使用 JObject.Parse()JArray.Parse() 来解析 JSON 字符串到这些动态类型:

using System;
using Newtonsoft.Json.Linq; // 引入 Newtonsoft.Json.Linqpublic class JsonDynamicParsingExample
{public static void Main(string[] args){string dynamicJsonString = @"{""metadata"": {""timestamp"": ""2023-10-27T10:00:00Z"",""version"": 1.5},""results"": [{ ""id"": 10, ""status"": ""success"" },{ ""id"": 20, ""status"": ""failed"", ""errorDetail"": ""Timeout"" }],""settings"": null}";try{// 解析为 JObject (如果 JSON 根是对象)JObject jsonObject = JObject.Parse(dynamicJsonString);// 动态访问属性(使用索引器)// 可以直接强制类型转换,但如果属性不存在或类型不匹配会抛异常string timestamp = (string)jsonObject["metadata"]["timestamp"];double version = (double)jsonObject["metadata"]["version"];Console.WriteLine($"Timestamp: {timestamp}");Console.WriteLine($"Version: {version}");// 访问嵌套数组JArray resultsArray = (JArray)jsonObject["results"];if (resultsArray != null) // 始终检查 JArray 是否为 null{Console.WriteLine("Results:");foreach (JToken resultToken in resultsArray) // 遍历数组中的每个元素 (JObject){int id = resultToken.Value<int>("id"); // 使用 Value<T>(key) 安全获取子属性值string status = resultToken.Value<string>("status");string errorDetail = resultToken.Value<string>("errorDetail"); // 如果属性不存在,Value<string> 会返回 nullConsole.WriteLine($"  Id: {id}, Status: {status}, Error Detail: {errorDetail ?? "N/A"}");}}// 访问可能为 null 的属性JToken settingsToken = jsonObject["settings"];Console.WriteLine($"Settings token type: {settingsToken.Type}"); // 输出: NullJToken missingToken = jsonObject["nonexistentKey"];Console.WriteLine($"Missing token: {missingToken}"); // 输出空行 (C# null)// 修改 JSON 结构 (JObject/JArray 支持修改)jsonObject["newStatus"] = "Processed";jsonObject["results"][0]["status"] = "completed"; // 修改第一个结果的状态Console.WriteLine("\nModified JSON:");// 可以将 JObject/JArray 转换为格式化后的 JSON 字符串Console.WriteLine(jsonObject.ToString(Formatting.Indented));}catch (JsonReaderException ex){Console.WriteLine($"JSON Parsing Error: {ex.Message}");}catch (Exception ex){// 捕获强制类型转换失败、访问 null token 的属性等异常Console.WriteLine($"发生错误: {ex.Message}");}}
}

使用 JToken/JObject/JArray 进行动态解析非常灵活,但牺牲了编译时类型安全,需要更多的运行时检查来确保数据存在且类型正确。

3. JToken 的“判空”:理解 C# null 与 JSON null

在使用 JToken 系列进行动态访问时,正确判断一个 JToken 是否“空”或“不存在”非常重要,这也是初学者常见的困惑点。

  • C# null 引用: 当你使用索引器(如 jsonObject["missing_key"])尝试访问一个在 JSON 中 不存在 的属性时,Newtonsoft.Json 会返回 C# 的 null 引用。
  • JSON null 值: JSON 本身支持 null 值 ("key": null)。当解析到这样的值时,你会得到一个有效的 JToken 对象,它的 Type 属性是 JTokenType.Null

如何判断:

using Newtonsoft.Json.Linq;
using System;string json = @"{ ""name"": ""Test"", ""nullableAge"": null, ""emptyArray"": [], ""emptyObject"": {} }";
JObject obj = JObject.Parse(json);JToken existingToken = obj["name"];          // 代表一个字符串值
JToken nullableToken = obj["nullableAge"];    // 代表 JSON null 值
JToken missingToken = obj["nonexistentKey"];  // 是 C# null 引用
JToken emptyArrayToken = obj["emptyArray"];  // 代表一个空数组
JToken emptyObjectToken = obj["emptyObject"]; // 代表一个空对象// 1. 检查是否是 C# 的 null 引用 (属性不存在)
if (missingToken == null)
{Console.WriteLine("missingToken 是 C# null"); // 输出
}// 2. 检查是否代表 JSON null 值 ("key": null)
if (nullableToken != null && nullableToken.Type == JTokenType.Null)
{Console.WriteLine("nullableToken 代表 JSON null 值"); // 输出
}// 3. 最常见的组合检查:属性不存在 或 属性值为 JSON null
bool IsNullOrMissing(JToken token)
{return token == null || token.Type == JTokenType.Null;
}if (IsNullOrMissing(missingToken)) Console.WriteLine("missingToken is null or JSON null"); // 输出
if (IsNullOrMissing(nullableToken)) Console.WriteLine("nullableToken is null or JSON null"); // 输出
if (!IsNullOrMissing(existingToken)) Console.WriteLine("existingToken 不是 null 或 JSON null"); // 输出// 4. 检查是否是空数组或空对象
if (emptyArrayToken is JArray arr && arr.Count == 0)
{Console.WriteLine("emptyArrayToken 是一个空数组"); // 输出
}if (emptyObjectToken is JObject objToken && objToken.Count == 0)
{Console.WriteLine("emptyObjectToken 是一个空对象"); // 输出
}

理解这几者之间的区别,是高效使用 JToken 的关键。

第二部分:发送 application/json POST 请求

发送 POST 请求并附带 JSON 数据是与 Web API 交互的基本操作。在 .NET 中,我们通常使用 HttpClient 类来完成 HTTP 请求。结合 Newtonsoft.Json,我们可以轻松地将 C# 对象序列化为 JSON 并作为请求体发送。

以下是具体步骤:

  1. 创建要发送数据的 C# 对象:
    定义一个类来表示你想要发送的数据结构。
    using System.Collections.Generic;public class OrderRequest{public string ProductId { get; set; }public int Quantity { get; set; }public string CustomerName { get; set; }public decimal TotalAmount { get; set; }public List<string> Options { get; set; }}
  1. 使用 HttpClient 发送 POST 请求:
    using System;using System.Net.Http;using System.Text; // For Encodingusing System.Threading.Tasks; // For async/awaitusing System.Collections.Generic; // For List<string>using Newtonsoft.Json; // For JsonConvertpublic class HttpClientPostExample{// 最佳实践: 重用 HttpClient 实例private static readonly HttpClient _httpClient = new HttpClient();public static async Task PostJsonData(string url, OrderRequest orderDetails){try{// 1. 将 C# 对象序列化为 JSON 字符串string jsonPayload = JsonConvert.SerializeObject(orderDetails);Console.WriteLine($"Sending JSON payload: {jsonPayload}");// 2. 创建 StringContent,指定内容、编码和 Content-Type 为 application/jsonvar content = new StringContent(jsonPayload, Encoding.UTF8, "application/json");// 3. 使用 HttpClient 发送 POST 请求HttpResponseMessage response = await _httpClient.PostAsync(url, content);// 4. 检查响应状态码// response.EnsureSuccessStatusCode(); // 如果状态码不是 2xx 会抛异常Console.WriteLine($"Response Status Code: {response.StatusCode}");// 5. 读取响应内容 (如果需要)string responseBody = await response.Content.ReadAsStringAsync();Console.WriteLine($"Response Body: {responseBody}");// 6. 如果响应也是 JSON,可以反序列化// try// {//     // 假设响应是一个表示处理结果的 JSON 对象//     var responseResult = JsonConvert.DeserializeObject<OrderResponse>(responseBody);//     Console.WriteLine($"Order Status: {responseResult.Status}");// }// catch (JsonReaderException jsonEx)// {//     Console.WriteLine($"Failed to parse response body as JSON: {jsonEx.Message}");// }}catch (HttpRequestException e){Console.WriteLine($"HTTP Request Error: {e.Message}");// 在 .NET 5+ 可以通过 e.StatusCode 获取具体状态码}catch (Exception ex){Console.WriteLine($"An unexpected error occurred: {ex.Message}");}}// 示例响应类 (如果你的 API 返回 JSON)public class OrderResponse{public string Status { get; set; }public string OrderId { get; set; }}public static async Task Main(string[] args){// 替换成你的实际 POST 请求 URLstring apiUrl = "YOUR_API_ENDPOINT_URL_HERE"; // 例如: "https://httpbin.org/post"// 创建要发送的数据对象var myOrder = new OrderRequest{ProductId = "ABC-123",Quantity = 2,CustomerName = "John Doe",TotalAmount = 150.75m,Options = new List<string> { "Gift Wrap", "Express Shipping" }};Console.WriteLine($"Sending order POST request to {apiUrl}...");// 调用发送方法await PostJsonData(apiUrl, myOrder);Console.WriteLine("Request process finished.");}}// 定义之前创建的 OrderRequest 类public class OrderRequest{public string ProductId { get; set; }public int Quantity { get; set; }public string CustomerName { get; set; }public decimal TotalAmount { get; set; }public List<string> Options { get; set; }}
}

关键点解释:

  • HttpClient 生命周期: 在示例中使用了静态的 _httpClient 实例。这是推荐的做法,避免了创建和销毁过多 HttpClient 实例可能导致的 Socket Exhaustion 问题。
  • JsonConvert.SerializeObject(orderDetails):OrderRequest 对象转换为 JSON 字符串。Newtonsoft.Json 会处理属性名、值类型等。
  • new StringContent(...): 创建一个 HttpContent 对象,它承载了要发送的数据。我们传入 JSON 字符串,指定编码为 Encoding.UTF8,并设置 Content-Type"application/json"。这个 Content-Type 头部是服务器用来识别请求体数据格式的关键。
  • await _httpClient.PostAsync(url, content): 发送异步 POST 请求。HttpClient 会将 content 作为请求体发送到指定的 URL。
  • 异步操作 (async/await): HTTP 请求是 I/O 密集型操作,使用异步方式 (async/await) 可以避免阻塞调用线程,提高应用程序的响应性和可伸缩性,特别是在处理多个并发请求时。

总结

Newtonsoft.Json 是一个强大而灵活的库,为 C# 开发者提供了完整的 JSON 处理能力。无论是将复杂的 JSON 数据映射到强类型 C# 对象进行安全可靠的访问,还是使用 JToken 系列进行动态探索和操作未知结构的 JSON,它都能胜任。结合 HttpClient 发送 application/json 类型的 POST 请求,是现代 C# 应用与 Web API 交互的基石。

虽然 .NET Core 3.0 以后引入了内置的 System.Text.Json,它在某些场景下提供更好的性能,并且是微软官方在新的 .NET 版本中推荐的内置 JSON 库。然而,Newtonsoft.Json 凭借其丰富的功能集、成熟稳定性和庞大的现有代码库,在许多项目中仍然是不可或缺的选择。

希望本文能帮助你更好地理解和应用 Newtonsoft.Json 在 C# 中的 JSON 解析和 POST 请求场景!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/78566.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Debian10系统安装,磁盘分区和扩容

1、说明 过程记录信息有些不全&#xff0c;仅作为参考。如有其它疑问&#xff0c;欢迎留言。 2、ISO下载 地址&#xff1a;debian-10.13.0镜像地址 3、开始安装 3.1、选择图形界面 3.2、选择中文语言 3.3、选择中国区域 3.4、按照提示继续 3.5、选择一个网口 3.6、创建管…

1.10软考系统架构设计师:优秀架构设计师 - 练习题附答案及超详细解析

优秀架构设计师综合知识单选题 每道题均附有答案解析&#xff1a; 题目1 衡量优秀系统架构设计师的核心标准不包括以下哪项&#xff1f; A. 技术全面性与底层系统原理理解 B. 能够独立完成模块开发与调试 C. 与利益相关者的高效沟通与协调能力 D. 对业务需求和技术趋势的战略…

MPI Code for Ghost Data Exchange in 3D Domain Decomposition with Multi-GPUs

MPI Code for Ghost Data Exchange in 3D Domain Decomposition with Multi-GPUs Here’s a comprehensive MPI code that demonstrates ghost data exchange for a 3D domain decomposition across multiple GPUs. This implementation assumes you’re using CUDA-aware MPI…

计算机考研精炼 计网

第 19 章 计算机网络体系结构 19.1 基本概念 19.1.1 计算机网络概述 1.计算机网络的定义、组成与功能 计算机网络是一个将分散的、具有独立功能的计算机系统&#xff0c;通过通信设备与线路连接起来&#xff0c;由功能完善的软件实现资源共享和信息传递的系统。 …

KUKA机器人自动备份设置

在机器人的使用过程中&#xff0c;对机器人做备份不仅能方便查看机器人的项目配置与程序&#xff0c;还能防止机器人项目和程序丢失时进行及时的还原&#xff0c;因此对机器人做备份是很有必要的。 对于KUKA机器人来说&#xff0c;做备份可以通过U盘来操作。也可以在示教器上设…

【wpf】 WPF中实现动态加载图片浏览器(边滚动边加载)

WPF中实现动态加载图片浏览器&#xff08;边滚动边加载&#xff09; 在做图片浏览器程序时&#xff0c;遇到图片数量巨大的情况&#xff08;如几百张、上千张&#xff09;&#xff0c;一次性加载所有图片会导致界面卡顿甚至程序崩溃。 本文介绍一种 WPF Prism 实现动态分页加…

Kubernetes》》k8s》》Taint 污点、Toleration容忍度

污点 》》 节点上 容忍度 》》 Pod上 在K8S中&#xff0c;如果Pod能容忍某个节点上的污点&#xff0c;那么Pod就可以调度到该节点。如果不能容忍&#xff0c;那就无法调度到该节点。 污点和容忍度的概念 》》污点等级——>node 》》容忍度 —>pod Equal——>一种是等…

SEO长尾关键词优化核心策略

内容概要 在搜索引擎优化领域&#xff0c;长尾关键词因其精准的流量捕获能力与较低的竞争强度&#xff0c;已成为提升网站自然流量的核心突破口。本文围绕长尾关键词优化的全链路逻辑&#xff0c;系统拆解从需求洞察到落地执行的五大策略模块&#xff0c;涵盖用户搜索意图解析…

AWS中国区ICP备案全攻略:流程、注意事项与最佳实践

导语 在中国大陆地区开展互联网业务时,所有通过域名提供服务的网站和应用必须完成ICP备案(互联网内容提供商备案)。对于选择使用AWS中国区(北京/宁夏区域)资源的用户,备案流程因云服务商的特殊运营模式而有所不同。本文将详细解析AWS中国区备案的核心规则、操作步骤及避坑…

计算机视觉——通过 OWL-ViT 实现开放词汇对象检测

介绍 传统的对象检测模型大多是封闭词汇类型&#xff0c;只能识别有限的固定类别。增加新的类别需要大量的注释数据。然而&#xff0c;现实世界中的物体类别几乎无穷无尽&#xff0c;这就需要能够检测未知类别的开放式词汇类型。对比学习&#xff08;Contrastive Learning&…

大语言模型的“模型量化”详解 - 04:KTransformers MoE推理优化技术

基本介绍 随着大语言模型&#xff08;LLM&#xff09;的规模不断扩大&#xff0c;模型的推理效率和计算资源的需求也在迅速增加。DeepSeek-V2作为当前热门的LLM之一&#xff0c;通过创新的架构设计与优化策略&#xff0c;在资源受限环境下实现了高效推理。 本文将详细介绍Dee…

排序算法详解笔记

评价维度 运行效率就地性稳定性 自适应性&#xff1a;自适应排序能够利用输入数据已有的顺序信息来减少计算量&#xff0c;达到更优的时间效率。自适应排序算法的最佳时间复杂度通常优于平均时间复杂度。 是否基于比较&#xff1a;基于比较的排序依赖比较运算符&#xff08;…

【“星瑞” O6 评测】 — llm CPU部署对比高通骁龙CPU

前言 随着大模型应用场景的不断拓展&#xff0c;arm cpu 凭借其独特优势在大模型推理领域的重要性日益凸显。它在性能、功耗、架构适配等多方面发挥关键作用&#xff0c;推动大模型在不同场景落地 1. CPU对比 星睿 O6 CPU 采用 Armv9 架构&#xff0c;集成了 Armv9 CPU 核心…

Ocelot的应用案例

搭建3个项目&#xff0c;分别是OcelotDemo、ServerApi1和ServerApi2这3个项目。访问都是通过OcelotDemo进行轮训转发。 代码案例链接&#xff1a;https://download.csdn.net/download/ly1h1/90715035 1.架构图 2.解决方案结构 3.步骤一&#xff0c;添加Nuget包 4.步骤二&…

DeepSeek+Dify之五工作流引用API案例

DeepSeekDify之四Agent引用知识库案例 文章目录 背景整体流程测试数据用到的节点开始HTTP请求LLM参数提取器代码执行结束 实现步骤1、新建工作流2、开始节点3、Http请求节点4、LLM节点&#xff08;大模型检索&#xff09;5、参数提取器节点&#xff08;提取大模型检索后数据&am…

《从分遗产说起:JS 原型与继承详解》

“天天开心就好” 先来讲讲概念&#xff1a; 原型&#xff08;Prototype&#xff09; 什么是原型&#xff1f; 原型是 JavaScript 中实现对象间共享属性和方法的机制。每个 JavaScript 对象&#xff08;除了 null&#xff09;都有一个内部链接指向另一个对象&#xff0c;这…

立马耀:通过阿里云 Serverless Spark 和 Milvus 构建高效向量检索系统,驱动个性化推荐业务

作者&#xff1a;厦门立马耀网络科技有限公司大数据开发工程师 陈宏毅 背景介绍 行业 蝉选是蝉妈妈出品的达人选品服务平台。蝉选秉持“陪伴达人赚到钱”的品牌使命&#xff0c;致力于洞悉达人变现需求和痛点&#xff0c;提供达人选高佣、稳变现、速响应的选品服务。 业务特…

Android显示学习笔记本

根据博客 Android-View 绘制原理(01)-JAVA层分析_android view draw原理分析-CSDN博客 提出了我的疑问 Canvas RenderNode updateDisplayListDirty 这些东西的关系 您的理解在基本方向上是对的&#xff0c;但让我详细解释一下 Android 中 updateDisplayListDirty、指令集合、…

JavaWeb学习打卡-Day4-会话技术、JWT、Filter、Interceptor

会话技术 会话&#xff1a;用户打开浏览器&#xff0c;访问web服务器的资源&#xff0c;会话建立&#xff0c;直到有一方断开连接&#xff0c;会话结束。在一次会话中可以包含多次请求和响应。会话跟踪&#xff1a;一种维护浏览器状态的方法&#xff0c;服务器需要识别多次请求…

让数据优雅落地:用 serde::Deserialize 玩转结构体实体

前言 想象一下,服务器突然飞来一堆 JSON 数据,就像一群无头苍蝇冲进办公室,嗡嗡作响,横冲直撞。此刻,你的任务,就是把这群“迷路数据”安置进正确的格子里,分门别类,秩序井然,不混不乱,不漏一只。 好在 Rust 早就为我们备好瑞士军刀:serde::Deserialize。它不仅刀…