c# System.Text.Json 精讲
本文内容来自我写的开源电子书《WoW C#》,现在正在编写中,可以去WOW-Csharp/学习路径总结.md at master · sogeisetsu/WOW-Csharp (github.com)来查看编写进度。预计2021年年底会完成编写,2022年2月之前会完成所有的校对和转制电子书工作,争取能够在2022年将此书上架亚马逊。编写此书的目的是因为目前.NET市场相对低迷,很多优秀的书都是基于.NET framework框架编写的,与现在的.NET 6相差太大,正规的.NET 5学习教程现在几乎只有MSDN,可是MSDN虽然准确优美但是太过琐碎,没有过阅读开发文档的同学容易一头雾水,于是,我就编写了基于.NET 5的《WoW C#》。本人水平有限,欢迎大家去本书的开源仓库sogeisetsu/WOW-Csharp关注、批评、建议和指导。
Json解析
json是一种类似于通过键值对来储存数据的格式,在对数据库进行操作的时候,通常会把类数据转为json格式,然后储存在数据库里面,使用的时候再将json转为类的实例化对象。java的springboot框架的一整套解决方案里面可以通过mybatis和fastjson完成这个操作。在web的前后端数据传输中,一般也是用json作为数据的载体,JavaScript有着对json比较完备的支持。
Json格式概述
基础
- 概念: JavaScript Object Notation JavaScript对象表示法
json现在多用于存储和交换文本信息的语法
进行数据的传输
JSON 比 XML 更小、更快,更易解析。
语法:
基本规则
- 数据在名称/值对中:json数据是由键值对构成的 - 键用引号(单双都行)引起来,也可以不使用引号 - 值得取值类型: 1. 数字(整数或浮点数) 2. 字符串(在双引号中) 3. 逻辑值(true 或 false) 4. 数组(在方括号中) {"persons":[{},{}]} 5. 对象(在花括号中) {"address":{"province":"陕西"....}} 6. null - 数据由逗号分隔:多个键值对由逗号分隔 - 花括号保存对象:使用{}定义json 格式 - 方括号保存数组:[]
JavaScript获取数据:
json对象.键名
json对象["键名"]
数组对象[索引]
遍历

解析
使用 C# 对 JSON 进行序列化和反序列化 - .NET | Microsoft Docs
会用到两个名词,序列化和反序列化,其中序列化是指将实例对象转换成json格式的字符串,反序列化则是逆向前面序列化的过程。
在序列化的过程中,默认情况下会只序列化公共读写的属性,可以通过System.Text.Json.Serialization的JsonInclude特性或者JsonSerializerOptions的IncludeFields属性来包含公有字段。通过System.Text.Json.Serialization的JsonInclude特性可以来自定义可以序列化的非公共属性访问器(即属性的访问修饰符为public,但是set访问器和get访问器的任意一方为非public)。这可能对使用惯了java的人来说不适应,事实上这是一种很合理的序列化要求,默认状况下,序列化器会序列化对象中的所有可读属性,反序列化所有可写属性,这种方式尊重了访问修饰符的作用。也可用开源的Newtonsoft.Json来序列化非公有属性。现在很多编程语言(包括.NET)能通过反射来获取私有属性本身就是不合理的,从.NET core能明显的感觉到.NET团队出于安全的考虑在限制反射的使用。
需要用到的namespace:
using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;
- 用
System.Text.Json的JsonSerializer.Serialize方法可以进行序列化。 - 用
System.Text.Json的JsonSerializer.Deserialize方法可以进行反序列化。 - 用
System.Text.Json.Serialization可以要序列化的类添加必要的特性,比如JsonPropertyName为属性序列化时重命名,再比如JsonInclude来定义序列化时要包含的字段。 - 用
System.Text.Encodings.Web和System.Text.Unicode来让特定的字符集在序列化的时候能够正常序列化而不是被转义成为\uxxxx,其中xxxx为字符的 Unicode 代码。事实上,默认情况下,序列化程序会转义所有非 ASCII 字符。
序列化
只将实例化对象转变成json字符串,假设有一个实例化对象weatherForecast,序列化方式如下:
string jsonString = JsonSerializer.Serialize(weatherForecast);
反序列化
指将json字符串序列化成实例化对象,书接前文,方式如下:
weatherForecast = JsonSerializer.Deserialize<WeatherForecastWithPOCOs>(jsonString);
JsonSerializerOptions
可以通过JsonSerializerOptions来指定诸如是否整齐打印和忽略Null值属性等信息。使用方式为将JsonSerializerOptions实例化之后再当作JsonSerializer.Serialize和JsonSerializer.Deserialize的参数。
关于JsonSerializerOptions的属性可以查看如何使用 System.Text.Json 实例化 JsonSerializerOptions | Microsoft Docs
先实例化一个JsonSerializerOptions对象,在初始化器里面定义各种属性:
JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions()
{
// 整齐打印
WriteIndented = true,
// 忽略值为Null的属性
IgnoreNullValues = true,
// 设置Json字符串支持的编码,默认情况下,序列化程序会转义所有非 ASCII 字符。 即,会将它们替换为 \uxxxx,其中 xxxx 为字符的 Unicode
// 代码。 可以通过设置Encoder来让生成的josn字符串不转义指定的字符集而进行序列化 下面指定了基础拉丁字母和中日韩统一表意文字的基础Unicode 块
// (U+4E00-U+9FCC)。 基本涵盖了除使用西里尔字母以外所有西方国家的文字和亚洲中日韩越的文字
Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.CjkUnifiedIdeographs),
// 反序列化不区分大小写
PropertyNameCaseInsensitive = true,
// 驼峰命名
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
// 对字典的键进行驼峰命名
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
// 序列化的时候忽略null值属性
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
// 忽略只读属性,因为只读属性只能序列化而不能反序列化,所以在以json为储存数据的介质的时候,序列化只读属性意义不大
IgnoreReadOnlyFields = true,
// 不允许结尾有逗号的不标准json
AllowTrailingCommas = false,
// 不允许有注释的不标准json
ReadCommentHandling = JsonCommentHandling.Disallow,
// 允许在反序列化的时候原本应为数字的字符串(带引号的数字)转为数字
NumberHandling = JsonNumberHandling.AllowReadingFromString,
// 处理循环引用类型,比如Book类里面有一个属性也是Book类
ReferenceHandler = ReferenceHandler.Preserve
};
然后在序列化和反序列化的时候jsonSerializerOptions对象当作参数传给JsonSerializer.Serialize和JsonSerializer.Deserialize:
string jsonBookA = JsonSerializer.Serialize(bookA, jsonSerializerOptions);
// 反序列化
BookA bookA1 = JsonSerializer.Deserialize<BookA>(jsonBookA, jsonSerializerOptions);
JsonSerializerOptions 常用属性概述
| 作用 | 值类型 | |
|---|---|---|
WriteIndented |
整齐打印,将此值设置为true后序列化的json字符串在打印的时候会进行自动缩进和换行。默认为false。 | bool |
IgnoreNullValues |
忽略值为Null的属性。默认为false。 | bool |
Encoder |
设置Json字符串支持的编码,默认情况下,序列化程序会转义所有非 ASCII 字符。 即,会将它们替换为 \uxxxx,其中 xxxx 为字符的 Unicode代码。 可以通过设置Encoder来让生成的josn字符串不转义指定的字符集而进行序列化。可设置为Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.CjkUnifiedIdeographs)来包含除使用西里尔字母以外所有西方国家的文字和亚洲中日韩越的文字 |
JavaScriptEncoder |
PropertyNameCaseInsensitive |
反序列化不区分键的大小写。默认为false。 | bool |
PropertyNamingPolicy |
序列化时属性的命名方式,常用的为JsonNamingPolicy.CamelCase设置成小写字母开头的驼峰命名。 |
JsonNamingPolicy |
DictionaryKeyPolicy |
序列化时对字典的string键进行小写字母开头的驼峰驼峰命名。 | JsonNamingPolicy |
DefaultIgnoreCondition |
指定一个条件,用于确定何时在序列化或反序列化过程中忽略具有默认值的属性。 默认值为 Never。常用值为JsonIgnoreCondition.WhenWritingDefault来忽略默认值属性。 |
JsonIgnoreCondition |
IgnoreReadOnlyFields |
序列化时忽略只读属性,因为只读属性只能序列化而不能反序列化,所以在以json为储存数据的介质的时候,序列化只读属性意义不大。默认为false。 | bool |
AllowTrailingCommas |
反序列化时,允许结尾有逗号的不标准json,默认为false。 | bool |
ReadCommentHandling |
反序列化时,允许有注释的不标准json,默认为false。 | bool |
NumberHandling |
使用NumberHandling = JsonNumberHandling.AllowReadingFromString可允许在反序列化的时候原本应为数字的字符串(带引号的数字)转为数字 |
JsonNumberHandling |
ReferenceHandler |
配置在读取和写入 JSON 时如何处理对象引用。使用ReferenceHandler = ReferenceHandler.Preserve仍然会在序列化和反序列化的时候保留引用并处理循环引用。 |
ReferenceHandler |
IncludeFields |
确定是否在序列化和反序列化期间处理字段。 默认值为 false。 |
bool |
System.Text.Json.Serialization 特性
可以为将要序列化和被反序列化而生成的类的属性和字段添加特性。
JsonInclude 包含特定public字段和非公共属性访问器
在序列化或反序列化时,使用 JsonSerializerOptions.IncludeFields 全局设置或 [JsonInclude] 特性来包含字段(必须是public),当应用于某个属性时,指示非公共的 getter 和 setter 可用于序列化和反序列化。 不支持非公共属性。
demo:
/// <summary>
/// 时间戳
/// </summary>
[JsonInclude]
public long timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds();
/// <summary>
/// 书的名称
/// </summary>
[JsonInclude]
public string Name { private get; set; } = "《书名》";
JsonPropertyName 自定义属性名称
若要设置单个属性的名称,请使用 [JsonPropertyName] 特性。
此特性设置的属性名称:
- 同时适用于两个方向(序列化和反序列化)。
- 优先于属性命名策略。
demo:
/// <summary>
/// 作者
/// </summary>
[JsonPropertyName("作者")]
public string Author
{
get { return _author; }
set { _author = value; }
}
JsonIgnore 忽略单个属性
阻止对属性进行序列化或反序列化。
demo:
/// <summary>
/// 书的出版商
/// </summary>
[JsonIgnore]
public string OutCompany { get => _outCompany; set => _outCompany = value; }
JsonExtensionData 处理溢出 JSON
反序列化时,可能会在 JSON 中收到不是由目标类型的属性表示的数据。可以将这些无法由目标类型的属性表示的数据储存在一个Dictionary<string, JsonElement>字典里面,方式如下:
/// <summary>
/// 储存反序列化时候的溢出数据
/// </summary>
[JsonExtensionData]
public Dictionary<string, JsonElement> ExtensionData { get; set; }
笔者的选择
在笔者的开发经验当中,json用的最多的就是前后端数据传输和数据库储存数据。对jsonSerializerOptions往往会选择这几个选项:
JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions()
{
// 整齐打印
WriteIndented = true,
// 忽略值为Null的属性
IgnoreNullValues = true,
// 设置Json字符串支持的编码,默认情况下,序列化程序会转义所有非 ASCII 字符。 即,会将它们替换为 \uxxxx,其中 xxxx 为字符的 Unicode
// 代码。 可以通过设置Encoder来让生成的josn字符串不转义指定的字符集而进行序列化 下面指定了基础拉丁字母和中日韩统一表意文字的基础Unicode 块
// (U+4E00-U+9FCC)。 基本涵盖了除使用西里尔字母以外所有西方国家的文字和亚洲中日韩越的文字
Encoder = JavaScriptEncoder.Create(UnicodeRanges.BasicLatin, UnicodeRanges.CjkUnifiedIdeographs, UnicodeRanges.CjkSymbolsandPunctuation),
// 反序列化不区分大小写
PropertyNameCaseInsensitive = true,
// 驼峰命名
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
// 对字典的键进行驼峰命名
DictionaryKeyPolicy = JsonNamingPolicy.CamelCase,
// 忽略只读属性,因为只读属性只能序列化而不能反序列化,所以在以json为储存数据的介质的时候,序列化只读属性意义不大
IgnoreReadOnlyFields = true,
// 允许在反序列化的时候原本应为数字的字符串(带引号的数字)转为数字
NumberHandling = JsonNumberHandling.AllowReadingFromString
};
尽量不使用JsonPropertyName特性,对有可能会用到json反序列化的类一定会用到JsonExtensionData特性来储存可能存在的溢出数据。JsonIgnore 和JsonInclude会广泛的使用而不用JsonSerializerOptions的IncludeFields来序列化所有字段。
LICENSE
已将所有引用其他文章之内容清楚明白地标注,其他部分皆为作者劳动成果。对作者劳动成果做以下声明:
copyright 2021 苏月晟,版权所有。

本作品由苏月晟采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
c# System.Text.Json 精讲的更多相关文章
- 【译】System.Text.Json 的下一步是什么
.NET 5.0 最近发布了,并带来了许多新特性和性能改进.System.Text.Json 也不例外.我们改进了性能和可靠性,并使熟悉 Newtonsoft.Json 的人更容易采用它.在这篇文章中 ...
- [译]试用新的System.Text.Json API
译注 可能有的小伙伴已经知道了,在.NET Core 3.0中微软加入了对JSON的内置支持. 一直以来.NET开发者们已经习惯使用Json.NET这个强大的库来处理JSON. 那么.NET为什么要增 ...
- 使用System.Text.Json处理Json文档以及部分坑
System.Text.Json处理Json文档需要用到JsonDocument,JsonElement,JsonProperty. JsonDocument就是一个表示Json文档的东西,JsonE ...
- 在.Net Core 3.0中尝试新的System.Text.Json API
.NET Core 3.0提供了一个名为System.Text.Json的全新命名空间,它支持reader/writer,文档对象模型(DOM)和序列化程序.在此博客文章中,我将介绍它如何工作以及如何 ...
- .netcore3.0 System.Text.Json 日期格式化
.netcore3.0 的json格式化不再默认使用Newtonsoft.Json,而是使用自带的System.Text.Json来处理. 理由是System.Text.Json 依赖更少,效率更高. ...
- In .net 4.8,calculate the time cost of serialization in BinaryFormatter,NewtonSoft.json,and System.Text.Json.JsonSerializer.Serialize
using ConsoleApp390.Model; using Newtonsoft.Json; using System; using System.Collections.Generic; us ...
- C# Serialization performance in System.Runtime.Serialization.Formatters.Binary.BinaryFormatter,Newtonsoft.Json.JsonConvert and System.Text.Json.JsonSerializer.Serialize
In .net core 3.0 using System;using System.Collections.Generic;using System.Collections;using System ...
- .NET Core 内置的 System.Text.Json 使用注意
System.Text.Json 是 .NET Core 3.0 新引入的高性能 json 解析.序列化.反序列化类库,武功高强,但毕竟初入江湖,炉火还没纯青,使用时需要注意,以下是我们在实现使用中遇 ...
- Net core 2.x 升级 3.0 使用自带 System.Text.Json 时区 踩坑经历
.Net Core 3.0 更新的东西很多,这里就不多做解释了,官方和博园大佬写得很详细 关于 Net Core 时区问题,在 2.1 版本的时候,因为用的是 Newtonsoft.Json,配置比较 ...
随机推荐
- 掌握BeanShell,轻松处理jmeter中的数据
作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15424558.html 博客主页:https://www.cnblogs.com/testero ...
- Upload-labs通关指南(下) 11-20
承接上篇,这次我们继续做下半部分. 有些题目有其他做法是针对于windows系统特性的,并不能在linux上奏效,因此不在考虑范围之内. Pass-11 制作图片马直接上传 copy a.jpg /a ...
- C++ 与 Visual Studio 2019 和 WSL(三)
头文件 如果不小心修改了 Linux C/C++ 标准头文件,可以下面这样操作进行恢复: 项目 → 重新扫描解决方案
- 【转载】[经验] 嵌入式stm32实用的排序算法 - 交换排序
Ⅰ.写在前面 前面写了关于ADC采集电压的文章,大家除了求平均的方式来处理采样值,还有没有使用到其他的方式来处理采集值呢? 在某些情况下就需要对一组数据进行排序,并提取头特定的数据出来使用. 排序的应 ...
- 微信小程序的发布流程
一.背景 在中大型的公司里,人员的分工非常仔细,一般会有不同岗位角色的员工同时参与同一个小程序项目.为此,小程序平台设计了不同的权限管理使得项目管理者可以更加高效管理整个团队的协同工作 以往我们在开发 ...
- 【二食堂】Beta - Scrum Meeting 6
Scrum Meeting 6 例会时间:5.19 18:30~18:50 进度情况 组员 当前进度 今日任务 李健 1. 实体标注的优化基本已经实现,后端有bug,还没有进行接口调用 issue 2 ...
- 【二食堂】Alpha - 测试报告
TextMarking Alpha阶段测试报告 前后端测试过程及结果 在Alpha阶段,测试工作紧跟后端开发进度,一下是我们所做的一些测试工作. 后端单元测试 测试代码可以在git仓库中查看,后端对所 ...
- stm32知识学习的先后顺序
这里大概的罗列了一些学习STM32的内容,以及学习顺序.如果是新手的话,建议边看中文手册和学习视频;如果是已经入门的,个人建议自己做一个项目,不论项目大小,当然里面会涉及到自己已经学习过的,或者是自己 ...
- 使用jQuery-UI来实现一个Ajax的自动完成功能(自动填充搜索框的下拉值)
首先你要在.net拓展包中去搜索 jquery ui (Combined Libray)安装这么个文件 第二部 在控制器中添加我们根据输入搜索框的值获取符合的记录集的action 第三步 有了 ...
- Python reload(sys) NameError: name 'reload' is not defined
转载:Python reload(sys) NameError: name 'reload' is not defined - vercont - 博客园 (cnblogs.com) 对于 Pytho ...