在C#中使用JSON

JSON简介

1. 什么是 JSON?

        JSON(JavaScript Object Notation)是一种轻量级的数据交换格式。它的语法基于 JavaScript 对象表示法,简单、易读,同时被许多编程语言支持。尽管它来源于 JavaScript,但它并不依赖于 JavaScript,许多语言(如 Python、Java、C#、PHP 等)都能够解析和生成 JSON。

常见用途:

API 数据交互:在客户端和服务器之间传递数据时,JSON 是常用格式,特别是前后端交互时.

配置文件:许多应用程序使用 JSON 来保存配置文件(例如 .json 文件)。

数据持久化:在数据库或文件系统中使用 JSON 来存储结构化数据。

2. JSON 的基本语法结构

JSON 的数据结构非常简单,主要包括以下两种类型:

对象(Object):由花括号 {} 包围的一组键值对,键是字符串,值可以是任何合法的 JSON 数据类型。

数组(Array):由方括号 [] 包围的一组值,值可以是任意 JSON 类型。

示例:

{"name": "John","age": 30,"isStudent": false,"courses": ["Math", "Science"],"address": {"city": "New York","zipcode": "10001"}
}

JSON 的基本元素:

字符串:用双引号包裹,如 "name": "John"

数字:可以是整数或浮点数,如 "age": 30

布尔值:true 或 false

数组:一个有序的值列表,用方括号 [] 包裹

对象:一个无序的键值对集合,用花括号 {} 包裹

空值:null

你不难看出JSON 本质上由三种主要元素构成:

对象(Object):键值对的集合,类似于字典。JSON 对象用 {} 表示,包含键值对(key-value pairs),键必须是字符串,值可以是任意合法的 JSON 元素(如数组、对象或基本值)。

数组(Array):有序的元素集合,类似于列表或数组(不代表C#的数组,只是体现一个有序集合)。JSON 数组用 [] 表示,数组中的每个元素可以是任意合法的 JSON 元素(如对象、数组或基本值)。

基本值(Value):JSON 的最基础元素,可以是字符串、数字、布尔值或 null。这部分数据不能再包含其他子元素。

这很重要:因为充分分析这三种元素自身以及他们之间的关系是JSON处理的关键.很多JSON库也是考虑了这三种概念实现的.

3. JSON 的优势(作用)

JSON 之所以成为数据交换的首选格式,离不开它的诸多优势:

轻量级:相比于 XML 等格式,JSON 占用的体积更小,结构更为简洁。

可读性好:人类易读,同时解析程序也易于编写。

支持数据类型丰富:可以直接表示对象、数组、字符串、数字、布尔值等常见的数据结构。

广泛支持:几乎所有编程语言都提供了用于解析和生成 JSON 的库或内置函数。

标准化格式:JSON 的格式有明确的标准,确保了跨语言、跨平台的兼容性。

灵活性高:可以嵌套任意复杂的对象和数组,适合复杂的数据结构。

4. JSON 的常见使用场景

API 通信

在现代 Web 开发中,前后端的通信常常依赖于 JSON。客户端发送 HTTP 请求时,通常使用 JSON 格式来传递数据,服务器也通过 JSON 格式返回数据。下面是一个简单的例子:

请求体(客户端向服务器发送的数据):

{"username": "john_doe","password": "123456"
}

响应体(服务器返回的数据):

{"status": "success","message": "Login successful","token": "abcdef123456"
}
配置文件

JSON 格式经常用于存储配置数据,因为它易于阅读和修改。例如,一个应用程序的配置文件可能如下:

{"app_name": "MyApp","version": "1.0.0","settings": {"theme": "dark","language": "en"}
}

本地数据存储

前端开发中,JSON 常被用来在本地存储数据(如浏览器的 localStorage 或 sessionStorage)。

数据序列化

当将对象或数据结构保存到文件或数据库时,通常需要将其序列化为字符串格式,JSON 就是常用的序列化格式之一。

5.JSON和C#类型之间的映射关系

在 C# 中,JSON 的基本元素与相应的数据类型有直接的对应关系。

1. 字符串

JSON:字符串用双引号包裹,表示文本数据。

示例:"name": "John"

C# 对应类型:string

在 C# 中,JSON 的字符串类型直接映射为 string 类型。

示例:

string name = "John";

2. 数字

JSON:数字可以是整数或浮点数,表示数值类型的数据。

示例:"age": 30

C# 对应类型:int、float、double

在 C# 中,整数可以映射为 int,浮点数可以映射为 float 或 double,根据具体需要选择类型。

示例:

int age = 30;
float price = 29.99f;
double pi = 3.14159;

3. 布尔值

JSON:布尔值表示为 true 或 false。

示例:"isStudent": false

C# 对应类型:bool

在 C# 中,布尔值映射为 bool 类型。

示例:

bool isStudent = false;

4. 数组

JSON:数组是一个有序的值列表,用方括号 [] 包裹,数组中的每个元素可以是任意 JSON 类型。

示例:"courses": ["Math", "Science"]

C# 对应类型:List<T> 或数组 T[]

在 C# 中,JSON 数组可以映射为 List<T>(泛型列表)或者普通数组 T[],其中 T 是数组中元素的类型。

示例:

List<string> courses = new List<string> { "Math", "Science" };
// 或者
string[] coursesArray = { "Math", "Science" };

5. 对象

JSON:对象是一个无序的键值对集合,用花括号 {} 包裹,每个键必须是字符串,值可以是任意 JSON 类型。

示例:"address": { "city": "New York", "zipcode": "10001" }

C# 对应类型:自定义类或 Dictionary<string, T>

在 C# 中,JSON 对象可以映射为自定义类,类中的属性对应 JSON 对象中的键值对。也可以使用 Dictionary<string, T> 来表示键值对集合,其中 T 表示值的类型。

示例(使用自定义类):

class Address
{public string City { get; set; }public string Zipcode { get; set; }
}Address address = new Address { City = "New York", Zipcode = "10001" };

示例(使用字典):

Dictionary<string, string> address = new Dictionary<string, string>
{{ "city", "New York" },{ "zipcode", "10001" }
};

6. 空值

JSON:空值表示为 null。

示例:"middleName": null

C# 对应类型:null

在 C# 中,JSON 的 null 对应 C# 中的 null 值。它可以应用于任何可空类型(如引用类型和 Nullable<T>)。

在 C# 中,JSON 的基本元素可以映射为相应的 C# 数据类型。这种映射使得我们可以轻松处理 JSON 数据,并与 C# 中的对象和类型进行交互。

6. 如何处理 JSON 数据

什么是序列化/反序列化

        我们首先要先铺垫一下什么是序列化/反序列化

        序列化反序列化是将对象和数据在不同格式之间转换的过程,主要用于数据持久化、网络传输等场景.在C#中我们的数据一般以对象形式存储在内存中,但是内存数据不能持久保存,你关机后或者程序关闭时数据就没了,那我们怎么把数据保存下来呢?

        答案就是序列化,我们常用的就是将对象序列化为JSON(当然不止JSON,只是JSON更常用),这样我们再将其(这个说的更清晰点就是字符串,JSON绝大多数情况是以字符串形式出现的,只不过你可以理解为是一种有一定格式或一定规则的字符串)保存在磁盘或者通过网络传递给其他人都很方便.

        理所当然的JSON转换为内存中的对象就是反序列化,常见的情景就是读取JSON格式的配置文件,先从磁盘读取出来再反序列化为对象,我们就可以十分方便的操作这个对象了.

怎么做?

        大多数编程语言都提供了用于解析(反序列化)和生成(序列化)JSON 数据的库或内置函数。

C# 提供了 System.Text.Json 和 Newtonsoft.Json(第三方库)来处理 JSON。

        我建议使用Newtonsoft.Json(NuGet Gallery | Newtonsoft.Json 13.0.3),这可以说是C#环境里最流行,最强大的一个库,经过二十年左右的发展支持绝大多数.net环境,目前在所有nuget包中下载量中排名第一.

常见用法

1. 使用 JsonConvert.SerializeObject 方法可以将 C# 对象转换为 JSON 字符串。

using Newtonsoft.Json;public class Person
{public string Name { get; set; }public int Age { get; set; }public bool IsStudent { get; set; }
}Person person = new Person { Name = "John", Age = 30, IsStudent = false };// 序列化为 JSON
string json = JsonConvert.SerializeObject(person);
Console.WriteLine(json);

得到(这就是一个字符串,包括首尾的花括号在内,前面提到{}代表一个对象,里面是无序的键值对)

{"Name":"John","Age":30,"IsStudent":false}

2.  使用 JsonConvert.DeserializeObject<T> 可以将 JSON 字符串反序列化为 C# 对象。

//这里的\是转义符,不是字符串自身的内容
string json = "{\"Name\":\"John\",\"Age\":30,\"IsStudent\":false}";// 反序列化为对象
Person person = JsonConvert.DeserializeObject<Person>(json);Console.WriteLine(person.Name);  // 输出 "John"
Console.WriteLine(person.Age);   // 输出 30

3.  将 JSON 数组转换为 C# 集合(如 List<T>)。

string jsonArray = "[{\"Name\":\"John\",\"Age\":30},{\"Name\":\"Jane\",\"Age\":25}]";// 反序列化为 List<Person>
List<Person> people = JsonConvert.DeserializeObject<List<Person>>(jsonArray);foreach (var person in people)
{Console.WriteLine($"{person.Name}, {person.Age}");
}
John, 30
Jane, 25

4. 处理嵌套对象

如果 JSON 中包含嵌套对象,Newtonsoft.Json 可以自动反序列化嵌套结构。

public class Address
{public string City { get; set; }public string Zipcode { get; set; }
}public class Person
{public string Name { get; set; }public Address Address { get; set; }
}string nestedJson = "{\"Name\":\"John\",\"Address\":{\"City\":\"New York\",\"Zipcode\":\"10001\"}}";// 反序列化嵌套的 JSON
Person person = JsonConvert.DeserializeObject<Person>(nestedJson);
Console.WriteLine($"{person.Name} lives in {person.Address.City}, {person.Address.Zipcode}");

5.JToken,JObject,JArray,JValue

上面提到JSON的基本组成元素:对象,数组,基本值,这对应看newtonjson提供的JObject,JArray,JValue三种类型,哪还有一个JToken,这个JToken是三种类型抽象类型,后三者继承自前者.

为什么提到这些类呢?因为更灵活!

        你注意上面例子,我们处理一个JSON需要先声明一个类型,有的时候我们声明了这个类型可能极少使用,那么这个时候我们声明一个类型似乎就有些没必要了.

        或者这个JSON数据的结构不是固定的,或是动态的的情况下.所以我们使用上面的类型.

string jsonString = "{\"name\": \"Alice\", \"age\": 25}";// 使用 JObject 解析
JObject obj = JObject.Parse(jsonString);// 动态访问字段
string name = (string)obj["name"];
int age = (int)obj["age"];Console.WriteLine($"Name: {name}, Age: {age}");

        请看JSON代表一个对象,如果不常用这个类型,那么我们直接认为它是一个JObject类型.这样我们转为JObject类型,再使用索引器直接拿到我们需要的数据.

        上述我们知道这是一个对象,所以我们使用JObject类型,那么我们连这个也不知道呢?无妨!掏出我们的JToken类型,这个类型是三个子类的父类,包含所有子类的行为,能够代表所有的JSON概念,无论它是对象,数组,还是基本值.

        

using Newtonsoft.Json.Linq;string jsonString = @"{'person': {'name': 'Alice','age': 25,'address': {'city': 'Wonderland','zipcode': '12345'},'phones': ['123-456-7890', '987-654-3210']}
}";// 解析为 JToken
JToken token = JToken.Parse(jsonString);// 动态访问嵌套字段
string name = (string)token["person"]["name"];
string city = (string)token["person"]["address"]["city"];
string phone = (string)token["person"]["phones"][0];Console.WriteLine($"Name: {name}, City: {city}, First Phone: {phone}");
using Newtonsoft.Json.Linq;string jsonString = @"{'name': 'Alice','age': 25,'address': {'city': 'Wonderland','zipcode': '12345'},'hobbies': ['reading', 'chess', 'running']
}";// 使用 JToken 解析
JToken token = JToken.Parse(jsonString);// 动态访问对象中的字段
string name = (string)token["name"];
int age = (int)token["age"];// 动态访问嵌套对象
string city = (string)token["address"]["city"];
string zipcode = (string)token["address"]["zipcode"];// 动态访问数组中的元素
string firstHobby = (string)token["hobbies"][0];
string secondHobby = (string)token["hobbies"][1];// 输出结果
Console.WriteLine($"Name: {name}, Age: {age}");
Console.WriteLine($"City: {city}, Zipcode: {zipcode}");
Console.WriteLine($"First Hobby: {firstHobby}, Second Hobby: {secondHobby}");

类型转换(对于JToken或它的子类)

        Newtonsoft.Json 不仅支持通过类型强制转换访问 JSON 数据,还提供了更加便捷的方法来进行类型转换。这些方法能够避免类型强制转换时潜在的异常风险,并提供更清晰的代码表达。

Newtonsoft.Json 提供了以下常用的类型转换方法

1.Value<T>() 方法(适用于基本类型)

        Value<T>() 是 JToken 提供的一个泛型方法,能够安全地将 JToken 的值转换为指定的类型。如果类型转换失败,它不会抛出异常,而是返回类型的默认值。

适用于想要避免显式的类型强制转换,并且希望代码更简洁、安全的场景。

JToken token = JToken.Parse(@"{ 'name': 'Alice', 'age': 25 }");string name = token["name"].Value<string>(); // 安全的类型转换int age = token["age"].Value<int>(); // 转换为 intConsole.WriteLine($"Name: {name}, Age: {age}");

        使用 Value<T>() 进行转换时,如果值不存在或者转换失败,它会返回类型的默认值(如 string 会返回 null,int 会返回 0),不会像类型强制转换那样抛出异常。

2.ToObject<T>() 方法

        ToObject<T>() 是另一个常用的方法,允许将 JToken 转换为一个具体的对象或类型。它适用于你希望将 JSON 数据反序列化为 C# 的具体类型(如类或结构体)的场景。

ToObject<T>() 方法通过反序列化来进行转换,因此适合用于复杂的数据结构转换。

// 定义一个类与 JSON 数据对应public class Person{public string Name { get; set; }public int Age { get; set; }}JToken token = JToken.Parse(@"{ 'name': 'Alice', 'age': 25 }");// 将 JToken 反序列化为具体的 Person 对象Person person = token.ToObject<Person>();Console.WriteLine($"Name: {person.Name}, Age: {person.Age}");

适合处理复杂的 JSON 数据结构,能够将整个 JSON 结构直接转换为一个 C# 对象。

它的灵活性使得你可以轻松地从 JSON 数据中创建 C# 类对象,而不用手动提取每一个字段。

3.TryGetValue<T>(out T result) 方法

        这是一个较为安全的访问方式,TryGetValue 尝试从 JToken 中获取指定类型的值,并通过返回布尔值来指示是否成功获取。

它适合在不确定 JSON 数据结构或类型时,安全地进行转换操作,避免抛出异常。

JToken token = JToken.Parse(@"{ 'name': 'Alice', 'age': 'not an integer' }");// 尝试安全获取值int age;bool success = token["age"].TryGetValue<int>(out age);if (success){Console.WriteLine($"Age: {age}");}else{Console.WriteLine("Failed to get a valid integer for age.");}

安全的类型转换方式,适合在 JSON 数据不可靠或结构复杂时使用。

它通过 out 参数来返回结果,能够避免异常。

强制类型转换 vs 提供的方法

强制类型转换(Explicit Casting)

        允许直接进行强制类型转换,比如 (string)token["name"] 或 (int)token["age"]。这种方式比较简洁,但是如果类型不匹配或值不存在,会抛出异常。

总结

Value<T>() 方法:提供了安全的类型转换方式,不会抛出异常,适合处理简单的数据访问场景,代码简洁。

ToObject<T>() 方法:适合将 JSON 直接转换为 C# 对象,特别是对于复杂的 JSON 结构,能够减少手动提取每个字段的工作量。

TryGetValue<T>() 方法:提供一种安全的方式来获取 JSON 数据中的值,适合在不确定数据结构或类型的情况下使用,防止异常的发生。

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

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

相关文章

RTE大会报名丨 重塑语音交互:音频技术和 Voice AI,RTE2024 技术专场第一弹!

Voice AI 实现 human-like 的最后一步是什么&#xff1f; AI 视频爆炸增长&#xff0c;新一代编解码技术将面临何种挑战&#xff1f; 当大模型进化到实时多模态&#xff0c;又将诞生什么样的新场景和玩法&#xff1f; 所有 AI Infra 都在探寻规格和性能的最佳平衡&#xff0…

美畅物联丨GB/T 28181系列之TCP/UDP被动模式和TCP主动模式

GB/T 28181《安全防范视频监控联网系统信息传输、交换、控制技术要求》作为我国安防领域的重要标准&#xff0c;为视频监控系统的建设提供了全面的技术指导和规范。该标准详细规定了视频监控系统的信息传输、交换和控制技术要求&#xff0c;在视频流传输方面&#xff0c;GB/T 2…

大厂面试真题:简单说下Redis的bigkey

什么是bigkey bigkey是指key对应的value所占的内存空间比较大&#xff0c;例如一个字符串类型的value可以最大存到512MB&#xff0c;一个列表类型的value最多可以存储23-1个元素。 如果按照数据结构来细分的话&#xff0c;一般分为字符串类型bigkey和非字符串类型bigkey。 字…

考研数据结构——C语言实现插入排序

插入排序是一种简单直观的比较排序算法&#xff0c;它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入。插入排序在实现上&#xff0c;通常采用in-place&#xff08;原地排序&#xff09;&#…

ceph rgw 桶分片之reshard

Ceph RGW&#xff08;RADOS Gateway&#xff09;的 reshard 功能是用来动态调整对象存储的分片&#xff08;shard&#xff09;数量&#xff0c;从而优化性能和存储利用率。随着数据量的增加&#xff0c;初始的分片设置可能无法满足性能需求&#xff0c;因此 reshard 功能允许用…

Git 与远程分支

90.远程仓库和分支 我们经常需要对远程仓库里的分支进行更新。 ‍ 当从远程库 clone 时&#xff0c;默认情况下&#xff0c;只会拉取 master ​分支&#xff0c;并且会将本地的 master 分支和远程的 master 分支关联起来&#xff1a; $ git branch * master‍ ‍ 推送本地…

17.第二阶段x86游戏实战2-线程发包和明文包

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…

kubernetes的网络

kubernetes网络模型 Kubernetes采用的是基于扁平地址空间的网络模型&#xff0c;集群中的每个Pod都有自己的IP地址&#xff0c;Pod之间不需要配置NAT就能直接通信&#xff0c;同一个Pod中的容器共享Pod的IP&#xff0c;能够通过localhost通信Pod容器内的通信 当Pod被调度到某个…

车辆重识别(去噪扩散概率模型)论文阅读2024/9/27

[2] Denoising Diffusion Probabilistic Models 作者&#xff1a;Jonathan Ho Ajay Jain Pieter Abbeel 单位&#xff1a;加州大学伯克利分校 摘要&#xff1a; 我们提出了高质量的图像合成结果使用扩散概率模型&#xff0c;一类潜变量模型从非平衡热力学的考虑启发。我们的最…

【hot100-java】【零钱兑换】

R9-dp篇 class Solution {public int coinChange(int[] coins, int amount) {int ncoins.length;int [][] fnew int[n1][amount1];//除2防止下面1溢出Arrays.fill(f[0],Integer.MAX_VALUE/2);f[0][0]0;for (int i0;i<n;i){for (int c0;c<amount;c){if(c<coins[i]) f[i…

5G NR 协议规范表(对应3GPP 协议编号)

文章目录 5G NR 协议规范表&#xff08;对应3GPP 协议编号&#xff09;5G 架构相关协议5G 新空口相关协议无线接入网相关协议终端相关协议 5G NR 协议规范表&#xff08;对应3GPP 协议编号&#xff09; 5G 架构相关协议 5G 新空口相关协议 无线接入网相关协议 终端相关协议

网页设计html心得

一&#xff0c;认识网页 说到网页&#xff0c;其实大家并不陌生 1.1网页究竟是什么&#xff1f; 网页主要由文字、图像和超链接等元素构成。当然&#xff0c;除了这些元素&#xff0c;网页中还可以包含音频、视频以及Flash等。 1.2网页是如何形成的呢&#xff1f; 1.特殊的…

uni-app在线预览pdf

这里推荐下载pdf.js 插件 PDF.js - Browse Files at SourceForge.net 特此注意 如果报 Promise.withResolvers is not a function 请去查看版本兼容问题 降低pdf.js版本提高node版本 下载完成后 在 static 文件夹下新建 pdf 文件夹&#xff0c;将解压文件放进 pdf 文件…

监控和日志管理:深入了解Nagios、Zabbix和Prometheus

在现代IT运维中&#xff0c;监控和日志管理是确保系统稳定性和性能的关键环节。本文将介绍三种流行的监控工具&#xff1a;Nagios、Zabbix和Prometheus&#xff0c;帮助您了解它们的特点、使用场景以及如何进行基本配置。 一、Nagios Nagios 是一个强大的开源监控系统&#x…

从0新建一个微信小程序实现一个简单跳转

首先 1.从这里下载开发工具 https://developers.weixin.qq.com/miniprogram/dev/framework/quickstart/getstart.htm 2. 等下载完毕后 创建一个空白项目 在pages目录下右键创建一个page : testUI,这时候会生成四个文件 新建一个文件夹 testUI 给他们放一起 3.增加一个按钮 …

蛋白质结构中模型的提取

在 Biopython 的 PDB 模块中,提取 PDB 结构中的 model 信息相对直观。在 PyMMCIF 包中,我们可以通过提取 atom_site 数据中的 pdbx_PDB_model_num 字段来识别结构中的不同模型。下面是如何使用这两个包分别提取结构的 model 信息的示例代码。 1. Biopython PDB 模块提取模型…

尚品汇-自动化部署-Jenkins的安装与环境配置(五十六)

目录&#xff1a; 自动化持续集成 &#xff08;1&#xff09;环境准备 &#xff08;2&#xff09;初始化 Jenkins 插件和管理员用户 &#xff08;3&#xff09;工作流程 &#xff08;4&#xff09;配置 Jenkins 构建工具 自动化持续集成 互联网软件的开发和发布&#xf…

多线程事务管理:Spring Boot 实现全局事务回滚

多线程事务管理:Spring Boot 实现全局事务回滚 在日常开发中,我们常常会遇到需要在多线程环境下进行数据库操作的场景。这类操作的挑战在于如何保证多个线程中的数据库操作要么一起成功,要么一起失败,即 事务的原子性。尤其是在多个线程并发执行的情况下,确保事务的一致性…

门面(外观)模式

简介 门面模式&#xff08;Facade Pattern&#xff09;又叫作外观模式&#xff0c;提供了一个统一的接口&#xff0c;用来访问子系统中的一群接口。其主要特征是定义了一个高层接口&#xff0c;让子系统更容易使用&#xff0c;属于结构型设计模式。 通用模板 创建子系统角色类…

多米诺骨牌(模拟)

初始化数据结构&#xff1a; 使用一个布尔数组 arr 来表示每个位置是否被占用。初始时所有位置均为 false&#xff08;未占用&#xff09;。使用一个 LinkedHashMap&#xff08;命名为 queue&#xff09;来记录最近的 R 操作的位置。这个结构可以保持插入顺序&#xff0c;方便后…