尝试新的 System.Text.Json 源生成器

在 .NET 6.0 的预览版中,我们使用 System.Text.Json 发布了一个新的 C# source generator 来帮助改进应用程序的性能。这里我们将回顾为什么我们要构建它,以及在你的应用程序中可以获得何种优势。

对于 System.Text.Json 源生成器,在 .NET 中,我们现在有一些用于 JSON 序列化的模型可供选择, JsonSerializer 是现有的模型,提供运行时反射支持,另外有两个编译时的源生成模型;这种方式的生成器生成优化后的序列化模型。或者两者都有。在所有的源生成场景中,生成的组件被直接传送给 JsonSerializer 做性能优化。下面是每种序列化模型提供的功能概览。

JsonSerializer JsonSerializer + pre-generatiing optimized serialization login JsonSerializer + pre-generating data access model
Increases serialization throughput No Yes No
Reduces start-up time No Yes Yes
Reduces private memory usage No Yes Yes
Eliminates runtime reflection No Yes Yes
Facilitates trim-safe app size reduction No Yes Yes
Supports all serialization features Yes No Yes

源生成器入门

源生成器可以用于任何 .NET 的 C# 项目,包括控制台应用,类库,Web 应用,以及 Blazor 应用程序。可以通过 System.TExt.Json 的 NuGet 包。在 .NET 6.0 即将到来的预览版 7 中将不再需要。

除了 .NET 6.0,源生成器与其它的 TFM 兼容,即 .NET 5.0 和更低的版本,.NET Framework 和 .NET Standard。API 集在各种 TFM 之间是一致的,但是不同 TFM 的可用的框架 API 不同,内部的实现是不同的。

对 .NET SDK 来说,最低的支持版本是 .NET 5.0

什么是 System.Txt.Json 源生成器

几乎所有的 .NET 序列化器的核心都是反射。反射对于特定场景提供了优异的能力,但是不包括作为高性能云原生应用程序 (特别) 基础的序列化/反序列,以及处理大量的 JSON 文档的场景。对于启动、内存使用和程序集修剪,反射都是问题所在。

一种方案是将运行时反射替换为编译时源生成。源生成器生成 C# 源代码文件,它可以被编译为库或者应用程序的一部分。在编译时生成代码对于 .NET 应用程序可以带来许多优势,包括增强性能。在 .NET 6 中,作为 System.Text.Json 的一部分,我们包括了新的源生成器。JSON 源生成器与 JsonSerializer 协同工作,可以通过多种方式配置。现有的 JsonSerializer 功能不变,所以是否使用新的源生成器是你的选择。JSON 源生成器的工作方式是将 JSON 可序列化类型的运行时检查转换到编译时,它生成一个静态模型来访问这些类型中的数据,直接使用 Utf8JsonWriter 优化序列化逻辑,或者同时使用两者。

为了使用源生成器,你可以定义一个派生于被称为 JsonSerializerContext 的新类型的分部类,使用新的 JsonSerializableAttribute 类来标注可序列化类型。

例如,对于一个简单的 Person 类型进行序列化。

namespace Test
{
internal class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}

需要为源生成器如下指定类型。

using System.Text.Json.Serialization;

namespace Test
{
[JsonSerializable(typeof(Person))]
internal partial class MyJsonContext : JsonSerializerContext
{
}
}

作为构建过程的一部分,源生成器会将 MyJsonContext 分部类填充为如下类型。

internal partial class MyJsonContext : JsonSerializerContext
{
public static MyJsonContext Default { get; } public JsonTypeInfo<Person> Person { get; } public MyJsonContext(JsonSerializerOptions options) { } public override JsonTypeInfo GetTypeInfo(Type type) => ...;
}

生成的源代码可以通过将它直接传递给 JsonSerializer 的新的重载方法中,以集成到编译的应用程序中。

// 序列化
Person person = new() { FirstName = "Jane", LastName = "Doe" };
byte[] utf8Json = JsonSerializer.SerializeToUtf8Bytes(
person, MyJsonContext.Default.Person); // 反序列化
person = JsonSerializer.Deserialize(utf8Json, MyJsonContext.Default.Person):

为什么使用源生成器?

JsonSerializer 是将 .NET 对象序列化到 JSON 串,以及从 JSON 串反序列回到 .NET 对象的工具。为了处理某种类型,序列化器需要得到如何访问对象成员的信息。在序列化的时候,序列化器需要访问对象的属性和字段读取器。简单来说,在反序列化的时候,序列化器需要访问构造函数来实例化对象,以及对象的字段与属性的设置器。

System.Text.Json 暴露在使用 JsonSerializer 进行序列化和反序列化时影响的机制,通过 JsonSerializerOptions (它支持运行时配置),还可以通过像 [JsonPropertyName(string)] 与 [JsonIgnore] 这样的特性 ( 这支持设计时配置 )。在序列化和反序列化类型的实例的时候,序列化器需要这些配置的信息,以便其使用。

当处理 JSON 可序列化类型的时候,序列化器需要在一个结构中访问关于对象成员和特性的配置信息,优化的格式。我们可以引用此结构化的信息作为必要的序列化元数据来序列化类型。

在以前版本的 System.Text.Json 中,序列化元数据只能在运行时得出,在对每种类型进行第一次序列化和反序列化的时候得出传递给序列化器。在这些元数据生成之后,序列化器执行实际的序列化和反序列化。这里得到的元数据将被缓存并在后继的 JSON 处理中被重用。生成元数据的环节基于反射实现,计算的复杂性在事件和分配上都是昂贵的。我们可以将该阶段称为序列化器的 “热身” 阶段。

System.Text.Json 源生成器帮助我们移除了该热身阶段,通过将运行时中的使用反射的可序列化类型检查转移到编译时进行。检查的结果可以作为源代码,用来初始化结构化的序列化元数据实例。生成器还可以生成高度优化的序列化逻辑,得益于一套 序列特性,指定的预先处理,默认情况下,生成器生成两种类型的源,但是可以配置为仅仅生成一套类型,或者每种可序列化类型一种。

生成的元数据包含在编译生成的程序集中,可以被初始化并直接传递给 JsonSerializer 以便序列化器不需要在运行时生成。这有助于缩减每种类型第一次序列化或者反序列化的时间。使用这些特性,使用该源生成器可以提供如下优势:

  • 增强序列化的吞吐量
  • 缩减启动时间
  • 缩减私有内存的使用
  • 移除对 System.Reflection 和 System.Reflection.Emit 的使用
  • 剪裁兼容的序列化,可以缩减应用程序的尺寸

JsonTypeInfo<T>, JsonTypeInfo, 与JsonSerializerContext 简介

Try the new System.Text.Json source generator | .NET Blog (microsoft.com)

尝试新的 System.Text.Json 源生成器的更多相关文章

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

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

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

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

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

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

  4. .NET Core 3.0 System.Text.Json 和 Newtonsoft.Json 行为不一致问题及解决办法

    行为不一致 .NET Core 3.0 新出了个内置的 JSON 库, 全名叫做尼古拉斯 System.Text.Json - 性能更高占用内存更少这都不是事... 对我来说, 很多或大或小的项目能少 ...

  5. [.Net Core 3.0+/.Net 5] System.Text.Json中时间格式化

    简介 .Net Core 3.0开始全新推出了一个名为System.Text.Json的Json解析库,用于序列化和反序列化Json,此库的设计是为了取代Json.Net(Newtonsoft.Jso ...

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

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

  7. 使用.Net6中的System.Text.Json遇到几个常见问题及解决方案

    前言 以前.NetCore是不内置JSON库的,所以大家都用Newtonsoft的JSON库,而且也确实挺好用的,不过既然官方出了标准库,那更方便更值得我们多用用,至少不用每次都nuget安装Newt ...

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

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

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

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

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

随机推荐

  1. 第16天:信息打点-CDN绕过&业务部署&漏洞回链&接口探针&全网扫描&反向邮件

    #CDN配置: 配置1:加速域名-需要启用加速的域名 配置2:加速区域-需要启用加速的地区 配置3:加速类型-需要启用加速的资源 #参考知识: 超级Ping:http://www.17ce.com/ ...

  2. 《Vue.js 设计与实现》读书笔记 - 第13章、异步组件与函数式组件

    第13章.异步组件与函数式组件 13.1 异步组件要解决的问题 用户可以简单通过 import 异步导入组件. <template> <component :is="asy ...

  3. SpringCloud入门(四)Ribbon负载均衡

    一.Ribbon负载均衡原理SpringCloud底层其实是利用了一个名为Ribbon的组件,来实现负载均衡功能的. SpringCloudRibbon的底层采用了一个拦截器,拦截了RestTempl ...

  4. 4.3 等比数列及其前n项和

    \(\mathbf{{\large {\color{Red} {欢迎到学科网下载资料学习}} } }\)[[高分突破系列] 高二数学下学期同步知识点剖析精品讲义! \(\mathbf{{\large ...

  5. 2021年1月国产数据库排行榜:OceanBase重回前三,TDSQL增长趋势最强劲!

    墨天轮国产数据库排行榜新年第一期已发布.2021年1月份排行榜前三甲依次为 TiDB .DaMeng.OceanBase .PingCAP TiDB 稳居冠军的宝座,短时间内难以撼动,开源的商业数据库 ...

  6. 什么是变量污染? let、const、var的区别?

    变量污染就是全局变量滥用,造成报错,覆盖等问题:简单讲就是使用了相同的标识符声明了全局变量,var关键字声明相同的变量名会覆盖,let.const重复声明相同的变量名会直接报错: var 可以声明提升 ...

  7. kotlin更多语言结构——>This表达式

    This表达式 为了表示当前的 接收者 我们使用 this 表达式: - 在类的成员中,this指的是该类的当前对象. - 在扩展函数或者带有接收者的函数字面值中,this 表示在点左侧传递的 接收者 ...

  8. 5.29 杭州站云原生 Meetup,邀您观看线上同步直播

    5 月 15 日在上海组织的云原生 Meetup,除了现场火爆.人数爆满之外,同步进行的线上直播也同样受到了广大社区小伙伴的关注,在线观看直播人数足有千人之众. 为了能让更多的社区小伙伴能够参与到 M ...

  9. 云原生爱好者周刊:利用 DNS 计算圆周率

    开源项目推荐 dns.toys dns.toys 是一个比较有创意的 DNS 服务器,它利用 DNS 协议提供了很多非常有趣的功能和服务.例如查询时间.天气.圆周率.单位换算等等. Submarine ...

  10. 【问题解决】Tomcat由低于8版本升级到高版本使用Tomcat自带连接池报错无法找到表空间的问题

    问题复现 项目上历史项目为解决漏洞扫描从Tomcat 6.0升级到了9.0版本,服务启动的日志显示如下警告,数据源是通过JNDI方式在server.xml中配置的,控制台上狂刷无法找到表空间的错误(没 ...