C# 9 预览版发布,新特性:代码生成器编译时反射

Posted DotNet开发跳槽

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# 9 预览版发布,新特性:代码生成器编译时反射相关的知识,希望对你有一定的参考价值。

前言

今天 .NET 官方博客宣布 C# 9 Source Generators 第一个预览版发布,这是一个用户已经喊了快 5 年特性,今天终于发布了。

简介

Source Generators 顾名思义代码生成器,它允许开发者在代码编译过程中获取查看用户代码并且生成新的 C# 代码参与编译过程,并且可以很好的与代码分析器集成提供 Intellisense、调试信息和报错信息,可以用它来做代码生成,因此也相当于是一个加强版本的编译时反射。

使用 Source Generators,可以做到这些事情:

  • 获取一个 Compilation 对象,这个对象表示了所有正在编译的用户代码,你可以从中获取 AST 和语义模型等信息

  • 可以向 Compilation 对象中插入新的代码,让编译器连同已有的用户代码一起编译

Source Generators 作为编译过程中的一个阶段执行:

编译运行 -> [分析源代码 -> 生成新代码] -> 将生成的新代码添加入编译过程 -> 编译继续。

上述流程中,中括号包括的内容即为 Source Generators 所参与的阶段和能做到的事情。

作用

.NET 明明具备运行时反射和动态 IL 织入功能,那这个 Source Generators 有什么用呢?

编译时反射 - 0 运行时开销

拿 ASP.NET Core 举例,启动一个 ASP.NET Core 应用时,首先会通过运行时反射来发现 Controllers、Services 等的类型定义,然后在请求管道中需要通过运行时反射获取其构造函数信息以便于进行依赖注入。然而运行时反射开销很大,即使缓存了类型签名,对于刚刚启动后的应用也无任何帮助作用,而且不利于做 AOT 编译。

Source Generators 将可以让 ASP.NET Core 所有的类型发现、依赖注入等在编译时就全部完成并编译到最终的程序集当中,最终做到 0 运行时反射使用,不仅利于 AOT 编译,而且运行时 0 开销。

除了上述作用之外,gRPC 等也可以利用此功能在编译时织入代码参与编译,不需要再利用任何的 MSBuild Task 做代码生成啦!

另外,甚至还可以读取 XML、JSON 直接生成 C# 代码参与编译,DTO 编写全自动化都是没问题的。

AOT 编译

Source Generators 的另一个作用是可以帮助消除 AOT 编译优化的主要障碍。

许多框架和库都大量使用反射,例如System.Text.Json、System.Text.RegularExpressions、ASP.NET Core 和 WPF 等等,它们在运行时从用户代码中发现类型。这些非常不利于 AOT 编译优化,因为为了使反射能够正常工作,必须将大量额外甚至可能不需要的类型元数据编译到最终的原生映像当中。

有了 Source Generators 之后,只需要做编译时代码生成便可以避免大部分的运行时反射的使用,让 AOT 编译优化工具能够更好的运行。

例子

INotifyPropertyChanged

写过 WPF 或 UWP 的都知道,在 ViewModel 中为了使属性变更可被发现,需要实现 INotifyPropertyChanged 接口,并且在每一个需要的属性的 setter 处除法属性更改事件: