本文内容来自我写的开源电子书《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格式概述

  • 基础

    1. 概念: JavaScript Object Notation JavaScript对象表示法
    • json现在多用于存储和交换文本信息的语法

    • 进行数据的传输

    • JSON 比 XML 更小、更快,更易解析。

    1. 语法:

    2. 基本规则

    -  数据在名称/值对中:json数据是由键值对构成的
    
    -  键用引号(单双都行)引起来,也可以不使用引号
    
    -  值得取值类型:
    
      1. 数字(整数或浮点数)
    
      2. 字符串(在双引号中)
    
      3. 逻辑值(true 或 false)
    
      4. 数组(在方括号中)	{"persons":[{},{}]}
    
      5. 对象(在花括号中) {"address":{"province":"陕西"....}}
    
      6. null
    
    -  数据由逗号分隔:多个键值对由逗号分隔
    
    -  花括号保存对象:使用{}定义json 格式
    
    -  方括号保存数组:[]
    1. JavaScript获取数据:
  1. json对象.键名

  2. json对象["键名"]

  3. 数组对象[索引]

  4. 遍历

解析

使用 C# 对 JSON 进行序列化和反序列化 - .NET | Microsoft Docs

会用到两个名词,序列化和反序列化,其中序列化是指将实例对象转换成json格式的字符串,反序列化则是逆向前面序列化的过程。

在序列化的过程中,默认情况下会只序列化公共读写的属性,可以通过System.Text.Json.SerializationJsonInclude特性或者JsonSerializerOptionsIncludeFields属性来包含公有字段。通过System.Text.Json.SerializationJsonInclude特性可以来自定义可以序列化的非公共属性访问器(即属性的访问修饰符为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.JsonJsonSerializer.Serialize方法可以进行序列化
  • System.Text.JsonJsonSerializer.Deserialize方法可以进行反序列化
  • System.Text.Json.Serialization可以要序列化的类添加必要的特性,比如JsonPropertyName为属性序列化时重命名,再比如JsonInclude来定义序列化时要包含的字段。
  • System.Text.Encodings.WebSystem.Text.Unicode来让特定的字符集在序列化的时候能够正常序列化而不是被转义成为 \uxxxx,其中 xxxx 为字符的 Unicode 代码。事实上,默认情况下,序列化程序会转义所有非 ASCII 字符。

序列化

只将实例化对象转变成json字符串,假设有一个实例化对象weatherForecast,序列化方式如下:

string jsonString = JsonSerializer.Serialize(weatherForecast);

反序列化

指将json字符串序列化成实例化对象,书接前文,方式如下:

weatherForecast = JsonSerializer.Deserialize<WeatherForecastWithPOCOs>(jsonString);

JsonSerializerOptions

可以通过JsonSerializerOptions来指定诸如是否整齐打印和忽略Null值属性等信息。使用方式为将JsonSerializerOptions实例化之后再当作JsonSerializer.SerializeJsonSerializer.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.SerializeJsonSerializer.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特性来储存可能存在的溢出数据。JsonIgnoreJsonInclude会广泛的使用而不用JsonSerializerOptionsIncludeFields来序列化所有字段。

LICENSE

已将所有引用其他文章之内容清楚明白地标注,其他部分皆为作者劳动成果。对作者劳动成果做以下声明:

copyright 2021 苏月晟,版权所有。


本作品由苏月晟采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

c# System.Text.Json 精讲的更多相关文章

  1. 【译】System.Text.Json 的下一步是什么

    .NET 5.0 最近发布了,并带来了许多新特性和性能改进.System.Text.Json 也不例外.我们改进了性能和可靠性,并使熟悉 Newtonsoft.Json 的人更容易采用它.在这篇文章中 ...

  2. [译]试用新的System.Text.Json API

    译注 可能有的小伙伴已经知道了,在.NET Core 3.0中微软加入了对JSON的内置支持. 一直以来.NET开发者们已经习惯使用Json.NET这个强大的库来处理JSON. 那么.NET为什么要增 ...

  3. 使用System.Text.Json处理Json文档以及部分坑

    System.Text.Json处理Json文档需要用到JsonDocument,JsonElement,JsonProperty. JsonDocument就是一个表示Json文档的东西,JsonE ...

  4. 在.Net Core 3.0中尝试新的System.Text.Json API

    .NET Core 3.0提供了一个名为System.Text.Json的全新命名空间,它支持reader/writer,文档对象模型(DOM)和序列化程序.在此博客文章中,我将介绍它如何工作以及如何 ...

  5. .netcore3.0 System.Text.Json 日期格式化

    .netcore3.0 的json格式化不再默认使用Newtonsoft.Json,而是使用自带的System.Text.Json来处理. 理由是System.Text.Json 依赖更少,效率更高. ...

  6. 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 ...

  7. 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 ...

  8. .NET Core 内置的 System.Text.Json 使用注意

    System.Text.Json 是 .NET Core 3.0 新引入的高性能 json 解析.序列化.反序列化类库,武功高强,但毕竟初入江湖,炉火还没纯青,使用时需要注意,以下是我们在实现使用中遇 ...

  9. Net core 2.x 升级 3.0 使用自带 System.Text.Json 时区 踩坑经历

    .Net Core 3.0 更新的东西很多,这里就不多做解释了,官方和博园大佬写得很详细 关于 Net Core 时区问题,在 2.1 版本的时候,因为用的是 Newtonsoft.Json,配置比较 ...

随机推荐

  1. FastAPI 学习之路(十三)Cookie 参数,Header参数

    系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...

  2. epoll实现快速ping

    概述 在VOIP的运营过程中,最常见的一类问题就是语音质量问题,网络间的丢包.延迟.抖动都会造成语音质量的体验下降. 当现网出现语音质量问题的时候,我们有没有工具能够快速的界定问题的边界,缩小排查的范 ...

  3. CSP-J 2021 复赛游记

    Day-1 啥也没干 晚上看了看洛谷的讨论,据说freopen在打开的最后要加 fclose(stdin);fclose(stdout); 不加也可.不过据说Linux在return 0之前不会自动关 ...

  4. Alpha发布声明

    项目 内容 这个作业属于哪个课程 2021春季软件工程(罗杰 任健) 这个作业的要求在哪里 Alpha-发布声明 我们是谁 删库跑路对不队 我们在做什么 题士 进度如何 进度总览 一.功能与特性 1. ...

  5. springboot读取配置文件中的信息

    在一个项目中,我们有时候会把一些配置信息写入到一个配置文件中,在java代码中读取配置文件的信息.在此记录下读取属性文件中的内容. 在springboot项目中,springboot的配置文件可以使用 ...

  6. 上午小测1 T1 木板 题解

    前言: WTCL,居然折磨煎蛋的性质都忘记了,WTCL. 考场上想出来了正解,就差一点就能A掉,挺难受的. 要记住一个数n可能会有一个大于\(\sqrt{n}\)的质因子..我忘记把它加进去了.... ...

  7. 【Golang详解】go语言中并发安全和锁

    go语言中并发安全和锁 首先可以先看看这篇文章,对锁有些了解 [锁]详解区分 互斥锁.⾃旋锁.读写锁.乐观锁.悲观锁 Mutex-互斥锁 Mutex 的实现主要借助了 CAS 指令 + 自旋 + 信号 ...

  8. python读取、写入txt文本内容

    转载:https://blog.csdn.net/qq_37828488/article/details/100024924 python常用的读取文件函数有三种read().readline().r ...

  9. 多线程--vthread

    vthread中包含两个类: vthread.vthread.pool vthread.vthread.thread 其中class pool的原型如下: class pool(builtins.ob ...

  10. jQuery根据地址获取经纬度

    一.HTML部分 1 @*景区位置*@ 2 <tr> 3 <th>景区名称:</th> 4 <td><input class="txt ...