c# 源生成器
创始人
2024-06-01 19:06:53
0

本文概述了 .NET Compiler Platform(“Roslyn”)SDK 附带的源生成器。 通过源生成器,C# 开发人员可以在编译用户代码时检查用户代码。 生成器可以动态创建新的 C# 源文件,这些文件将添加到用户的编译中。 这样,代码可以在编译期间运行。 它会检查你的程序以生成与其余代码一起编译的其他源文件。

源生成器是 C# 开发人员可以编写的一种新组件,允许执行两个主要操作:

检索表示正在编译的所有用户代码的编译对象。 可以检查此对象,并且可以编写适用于正在编译的代码的语法和语义模型的代码,就像现在使用分析器一样。

生成可在编译过程中添加到编译对象的 C# 源文件。 也就是说,在编译代码时,可以提供其他源代码作为编译的输入。

结合使用这两项操作能充分发挥源生成器的强大功能。 可以使用编译器在编译时构建的丰富元数据检查用户代码。 然后,生成器将 C# 代码发送回基于已分析数据的同一编译。 如果你熟悉 Roslyn 分析器,可以将源生成器视为可发出 C# 源代码的分析器。

源生成器作为编译阶段运行,如下所示:

在这里插入图片描述
源生成器是由编译器与任何分析器一起加载的 .NET Standard 2.0 程序集。 它在可以加载和运行 .NET Standard 组件的环境中使用。

常见方案

以下三种常规方法可用于检查用户代码,并基于当今技术所使用的分析生成信息或代码:

  • 运行时反射。
  • 处理 MSBuild 任务。
  • 交织中间语言 (IL)(本文未进行讨论)。
    源生成器可以是对以上每种方法的改进。

运行时反射

运行时反射是很久以前就添加到 .NET 中的一项强大技术。 使用该技术的场景不计其数。 一种常见的场景是在应用启动时对用户代码进行一定分析,并使用这些数据生成内容。

例如,ASP.NET Core 在 Web 服务首次运行时使用反射来发现你已定义的构造,使其能够“连接”控制器和 razor 页等内容。 虽然这使你能够使用强大的抽象编写简单的代码,但会在运行时影响性能:当 Web 服务或应用首次启动时,它无法接受任何请求,直到所有发现你的代码相关信息的运行时反射代码都运行完毕后才可以。 虽然这种性能影响不显著,但这是一个固定的成本,你无法在自己的应用中自我改进。

借助源生成器,启动的控制器发现阶段可以发生在编译时。 生成器可以分析源代码并发出“连接”应用所需的代码。 使用源生成器可能会加快启动时间,因为如今在运行时发生的操作可能会被推送到编译时。

处理 MSBuild 任务

源生成器也可以通过其他方式改进性能,从而发现类型,并不局限于运行时的反射。 有些场景需要多次调用 MSBuild C# 任务(称为 CSC),以便它们可以检查编译中的数据。 可以想象到的是,多次调用编译器会影响生成应用所需的总时间。 我们正在研究如何使用源生成器来避免像这样同时处理多项 MSBuild 任务,因为源生成器不仅提供了一定的性能优势,还允许工具在正确的抽象级别上运行。

源生成器可以提供的另一项功能是避免使用某些“强类型”的 API,例如 ASP.NET Core 在控制器和 razor 页面之间的路由方式。 使用源生成器时,路由可以为强类型,所需的字符串作为编译时细节生成。 这可以减少键入错误字符串文本导致请求未命中正确控制器的次数。

源生成器入门

在本指南中,你将了解如何使用 ISourceGenerator API 创建源生成器。
创建 .NET 控制台应用程序。 此示例使用 .NET 6。
将 Program 类替换为以下代码。 以下代码不使用顶级语句。 经典格式是必需的,因为第一个源生成器在该 Program 类中编写分部方法:

namespace ConsoleApp;partial partial class Program
{static void Main(string[] args){HelloFrom("Generated Code");}static partial void HelloFrom(string name);
}

接下来,我们将创建一个源生成器项目来实现 partial void HelloFrom 方法对应项。
创建一个以 netstandard2.0 目标框架名字对象 (TFM) 为目标的 .NET 标准库项目。 添加 NuGet 包 Microsoft.CodeAnalysis.Analyzers 和 Microsoft.CodeAnalysis.CSharp:

netstandard2.0allruntime; build; native; contentfiles; analyzers; buildtransitive

在这里插入图片描述
创建一个名为 HelloSourceGenerator.cs 的新 C# 文件,该文件指定你自己的源生成器,如下所示:

using Microsoft.CodeAnalysis;namespace ClassLibrary1
{/// /// Hello源生成/// [Generator]public class HelloSourceGenerator : ISourceGenerator{/// /// 执行代码生成/// /// public void Execute(GeneratorExecutionContext context){//代码生成在此处进行}/// /// 初始化/// /// public void Initialize(GeneratorInitializationContext context){//此操作不需要初始化}}
}

源生成器需要同时实现 Microsoft.CodeAnalysis.ISourceGenerator 接口,并且具有 Microsoft.CodeAnalysis.GeneratorAttribute。 并非所有源生成器都需要初始化,本示例实现就是这种情况,其中 ISourceGenerator.Initialize 为空。
将 ISourceGenerator.Execute 方法的内容替换为以下实现:

using Microsoft.CodeAnalysis;namespace ClassLibrary1
{/// /// Hello源生成/// [Generator]public class HelloSourceGenerator : ISourceGenerator{/// /// 执行代码生成/// /// public void Execute(GeneratorExecutionContext context){//代码生成在此处进行//查找主方法var mainMethod = context.Compilation.GetEntryPoint(context.CancellationToken);// 编译源代码string source = $@"// 
using System;namespace {mainMethod.ContainingNamespace.ToDisplayString()}
{{public static partial class {mainMethod.ContainingType.Name}{{static partial void HelloFrom(string name) =>Console.WriteLine($""Generator says: Hi from '{{name}}'"");}}
}}
";var typeName = mainMethod.ContainingType.Name;//将源代码添加到编译中context.AddSource($"{typeName}.g.cs", source);}/// /// 初始化/// /// public void Initialize(GeneratorInitializationContext context){//此操作不需要初始化}}
}

从 context 对象中,我们可以访问编译的入口点或 Main 方法。 mainMethod 实例是一个 IMethodSymbol,它表示一个方法或类似方法的符号(包括构造函数、析构函数、运算符或属性/事件访问器)。 Microsoft.CodeAnalysis.Compilation.GetEntryPoint 方法返回程序的入口点的 IMethodSymbol。 其他方法使你可以查找项目中的任何方法符号。 在此对象中,我们可以推理包含的命名空间(如果存在)和类型。 此示例中的 source 是一个内插字符串,它对要生成的源代码进行模板化,其中内插的缺口填充了包含的命名空间和类型信息。 使用提示名称将 source 添加到 context。 对于此示例,生成器创建一个新的生成的源文件,其中包含控制台应用程序中 partial 方法的实现。 可以编写源生成器来添加任何喜欢的源。

GeneratorExecutionContext.AddSource 方法中的 hintName 参数可以是任何唯一名称。 通常为该名称提供显式 C# 文件扩展名,例如 “.g.cs” 或 “.generated.cs”。 该文件名有助于将文件标识为正在生成源。

现在,我们有一个正常运行的生成器,但需要将其连接到控制台应用程序。 编辑原始的控制台应用程序项目,并添加以下内容,将项目路径替换为你在上面创建的 .NET Standard 项目中的路径:

Exenet6.0enableenable

在这里插入图片描述

控制台项目也需要安装相应的包
在这里插入图片描述

新引用不是传统的项目引用,必须手动编辑以包含 OutputItemType 和 ReferenceOutputAssembly 属性。 有关 ProjectReference 的 OutputItemType 和 ReferenceOutputAssembly 属性的更多信息,请参阅常见的 MSBuild 项目项:ProjectReference。

由于正在积极改进工具体验,因此可能需要重启 Visual Studio 才能看到 IntelliSense 并消除错误。

现在,运行控制台应用程序时,应会看到生成的代码运行并打印到屏幕。 控制台应用程序本身不实现 HelloFrom 方法,而是在编译过程中从源生成器项目生成的源。 以下文本是来自此应用程序的示例输出:
在这里插入图片描述
如果使用的是 Visual Studio,则可以看到源生成的文件。 在“解决方案资源管理器”窗口中,展开“依赖项”>“分析器”>“SourceGenerator”>“SourceGenerator.HelloSourceGenerator”,然后双击“Program.g.cs”文件。
在这里插入图片描述
打开这个生成的文件时,Visual Studio 将指示该文件是自动生成的并且无法编辑。
还可以设置生成属性以保存生成的文件并控制生成的文件的存储位置。 在控制台应用程序的项目文件中,将 元素添加到 ,将其值设置为 true。 再次生成项目。 现在,生成的文件是在 obj/Debug/net6.0/generated/SourceGenerator/SourceGenerator.HelloSourceGenerator 下创建的。 路径的组成部分映射到生成器的生成配置、目标框架、源生成器项目名称和完全限定的类型名称。 可以通过将 元素添加到应用程序的项目文件来选择较方便的输出文件夹。

调试代码
在这里插入图片描述
在这里插入图片描述
重新生成就会触发调试
在这里插入图片描述

直接打包引用是没有效果的,修改类库的项目文件

false

在这里插入图片描述
重新打包,新建项目引用

学习地址
https://github.com/TimChen44/CC.CodeGenerator

相关内容

热门资讯

编程安卓系统和鸿蒙主题,跨平台... 你有没有想过,手机的世界里,除了苹果的iOS和安卓的操作系统,还有个神秘的鸿蒙系统?今天,咱们就来聊...
哪个安卓机系统好用,探索安卓系... 你有没有想过,手机里的安卓系统就像是个大厨,不同的系统就像不同的烹饪手法,有的让你吃得津津有味,有的...
安卓如何控制苹果系统,从安卓到... 你知道吗?在这个科技飞速发展的时代,安卓和苹果两大操作系统之间的较量从未停歇。虽然它们各自有着忠实的...
安卓原生系统文件夹,安卓原生系... 你有没有发现,每次打开安卓手机,里面那些文件夹就像是一个个神秘的宝箱,里面藏着各种各样的宝贝?今天,...
基于安卓系统的游戏开发,从入门... 你有没有想过,为什么安卓手机上的游戏总是那么吸引人?是不是因为它们就像是你身边的好朋友,随时随地都能...
安卓系统怎样装驱动精灵,安卓系... 你那安卓设备是不是突然间有点儿不给力了?别急,今天就来手把手教你如何给安卓系统装上驱动精灵,让你的设...
如何本地安装安卓系统包,详细步... 你有没有想过,把安卓系统装在你的电脑上,是不是就像给电脑穿上了时尚的新衣?想象你可以在电脑上直接玩手...
安卓12卡刷系统教程,体验全新... 你有没有发现,你的安卓手机最近有点儿不给力了?运行速度慢得像蜗牛,是不是也想给它来个“换血大法”,让...
安卓系统无法打开swf文件,安... 最近是不是发现你的安卓手机有点儿不给力?打开SWF文件时,是不是总是出现“无法打开”的尴尬局面?别急...
鸿蒙系统依赖于安卓系统吗,独立... 你有没有想过,我们手机里的那个鸿蒙系统,它是不是真的完全独立于安卓系统呢?这个问题,估计不少手机控都...
适合安卓系统的图片软件,精选图... 手机里堆满了各种美美的照片,是不是觉得找起来有点头疼呢?别急,今天就来给你安利几款超级适合安卓系统的...
阴阳师安卓系统典藏,探寻阴阳师... 亲爱的阴阳师们,你是否在安卓系统上玩得如痴如醉,对那些精美的典藏式神们垂涎欲滴?今天,就让我带你深入...
安卓系统有碎片化缺点,系统优化... 你知道吗?在手机江湖里,安卓系统可是个响当当的大侠。它那开放、自由的个性,让无数手机厂商和开发者都为...
安卓4系统手机微信,功能解析与... 你有没有发现,现在市面上还有很多安卓4系统的手机在使用呢?尤其是那些喜欢微信的朋友们,这款手机简直就...
鸿蒙系统是安卓的盗版,从安卓“... 你知道吗?最近在科技圈里,关于鸿蒙系统的讨论可是热闹非凡呢!有人说是安卓的盗版,有人则认为这是华为的...
安卓系统怎么剪辑音乐,轻松打造... 你是不是也和我一样,手机里存了超多好听的歌,但是有时候想给它们来个变身,变成一段专属的旋律呢?别急,...
怎么把安卓手机系统变为pc系统... 你有没有想过,把你的安卓手机变成一台PC呢?听起来是不是有点酷炫?想象你可以在手机上玩电脑游戏,或者...
手机怎么装安卓11系统,手机安... 你有没有想过,让你的手机也来个“青春焕发”,升级一下系统呢?没错,就是安卓11系统!这个新系统不仅带...
安卓系统如何拼网络,构建高效连... 你有没有想过,你的安卓手机是怎么和网络“谈恋爱”的呢?没错,就是拼网络!今天,就让我带你一探究竟,看...
安卓系统怎么看小说,轻松畅享电... 你有没有发现,手机里装了那么多应用,最离不开的竟然是那个小小的小说阅读器?没错,就是安卓系统上的小说...