尝试新的 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. 信创环境经典版SuperMap iManager监控外部SuperMap iServer资源失败,无法监控目标GIS服务器CPU与内存使用情况

    一.问题环境 操作系统:银河麒麟kylin V10 CPU:鲲鹏920 SuperMap iServer 10.2.0 SuperMap iManager 10.2.1 二.现象 部署完经典版Supe ...

  2. 如何创建免费版本的ABP分离模块?

    如何创建免费版本的ABP分离模块? 由于ABP最近官方大改革,我们打开ABP.IO 官方会发现通过Cli创建模板的时候不能创建Trered类型的了 就是创建一个分层的解决方案,其中Web和Http A ...

  3. 使用composer创建项目时报错:Composer could not find the config file?

    使用composer创建项目时报错:Composer could not find the config file:C:\Composer ....? 一般报这个错就是composer安装的时候配置了 ...

  4. 如何理解iowait

    Linux中,%iowait 过高可能是个问题,严重的时候,它能使服务停止, 但问题是,多高才算高? 什么时候应该担心呢? 本文将讨论 iowait 的含义.相关的统计数据.原理以及 iowait的瓶 ...

  5. Python | os.path.join() method

    Python中的os.path.join()方法可以连接一个或多个路径组件. 此方法将各个路径组成部分,与每个非空部分路径组成部分恰好用一个目录分隔符(" /")连接起来. 如果要 ...

  6. threejs 父元素 相对位置 position 网格对象

    设置position都是相对于父元素的位置设置的 // 导入 threejs import * as THREE from "three"; import { OrbitContr ...

  7. input 的hidden 属性

    hidden 会隐藏input 标签内容显示,不占位置 : <input type="file" name="" id="" ref= ...

  8. 浅析Jvm

    浅析Jvm 基本概念 引言 Java 虚拟机(JVM,Java Virtual Machine)是 Java 生态系统的核心组成部分,它为 Java 应用程序提供了一个运行环境.JVM 的主要职责是将 ...

  9. 云原生周刊:Gateway API v1.1 发布 | 2024.6.3

    开源项目推荐 Grafana Tanka Tanka 是 Grafana 开发的一款用于 Kubernetes 的灵活.可重用和简洁的配置工具,是使用 YAML 进行 Kubernetes 配置的一种 ...

  10. 云原生周刊:KubeSphere 3.4.1 发布 | 2023.11.13

    开源项目推荐 Inspektor Gadget Inspektor Gadget 是一组用于调试和检查 Kubernetes 资源与应用程序的工具(或小工具).它在 Kubernetes 集群中管理 ...