c#的源代码生成器SourceGenerator/T4模板

简介

微软在 .NET 5 中引入了 Source Generator 的新特性,利用 Source Generator 我们可以在应用编译期间根据当前编译信息动态生成代码,而且可以在我们的 C# 代码中直接引用动态生成的代码,从而大大减少重复代码。

前面我们介绍过Emit和表达式树,本篇讲到的源代码生成器也是同样一个动态代码生成方案,他们之间的区别:

  • Source Generators在编译时运行,Emit在运行时运行,表达式树既可以在编译时生成代码,也可以在运行时构建代码
  • Source Generators和Emit通常用于生成方法和类型,而表达式树可以用于构建更复杂的表达式。
  • Source Generators是.NET Core及更高版本中的新功能,而Emit和表达式树在早期版本中就已存在。

源代码生成器有什么优点呢?

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

AOT 编译
Source Generators 的另一个作用是可以帮助消除 AOT 编译优化的主要障碍。许多框架和库都大量使用反射,非常不利于 AOT 编译优化,因为为了使反射能够正常工作,必须将大量额外甚至可能不需要的类型元数据编译到最终的原生映像当中。有了 Source Generators 之后,只需要做编译时代码生成便可以避免大部分的运行时反射的使用,让 AOT 编译优化工具能够更好的运行。

性能比较

表达式树 和 Source Generators 与 Emit 在简单的反射获取和写入私有属性时,哪种效率更高?

在简单的反射获取和写入属性的情况下,Source Generators 的效率可能会更高一些,因为它们可以在编译时生成额外的代码,并且生成的代码可以直接访问属性而无需使用反射。

通常情况下,使用 Emit 直接生成 IL 代码可能会比使用表达式树更高效,因为 Emit 可以直接生成底层的 IL 指令,而表达式树需要在运行时动态解释和执行。Emit 可以更接近底层的实现,因此通常性能会更好。但是其性能差异不明显。

总的来说:Source Generators > Emit >= 表达式树

Source Generators

另一种生成源代码的方案(T4模板)

手动生成源代码

此处评论已关闭