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

相关内容

热门资讯

电视安卓系统哪个品牌好,哪家品... 你有没有想过,家里的电视是不是该升级换代了呢?现在市面上电视品牌琳琅满目,各种操作系统也是让人眼花缭...
安卓会员管理系统怎么用,提升服... 你有没有想过,手机里那些你爱不释手的APP,背后其实有个强大的会员管理系统在默默支持呢?没错,就是那...
安卓系统软件使用技巧,解锁软件... 你有没有发现,用安卓手机的时候,总有一些小技巧能让你玩得更溜?别小看了这些小细节,它们可是能让你的手...
安卓系统提示音替换 你知道吗?手机里那个时不时响起的提示音,有时候真的能让人心情大好,有时候又让人抓狂不已。今天,就让我...
安卓开机不了系统更新 手机突然开不了机,系统更新还卡在那里,这可真是让人头疼的问题啊!你是不是也遇到了这种情况?别急,今天...
安卓系统中微信视频,安卓系统下... 你有没有发现,现在用手机聊天,视频通话简直成了标配!尤其是咱们安卓系统的小伙伴们,微信视频功能更是用...
安卓系统是服务器,服务器端的智... 你知道吗?在科技的世界里,安卓系统可是个超级明星呢!它不仅仅是个手机操作系统,竟然还能成为服务器的得...
pc电脑安卓系统下载软件,轻松... 你有没有想过,你的PC电脑上安装了安卓系统,是不是瞬间觉得世界都大不一样了呢?没错,就是那种“一机在...
电影院购票系统安卓,便捷观影新... 你有没有想过,在繁忙的生活中,一部好电影就像是一剂强心针,能瞬间让你放松心情?而我今天要和你分享的,...
安卓系统可以写程序? 你有没有想过,安卓系统竟然也能写程序呢?没错,你没听错!这个我们日常使用的智能手机操作系统,竟然有着...
安卓系统架构书籍推荐,权威书籍... 你有没有想过,想要深入了解安卓系统架构,却不知道从何下手?别急,今天我就要给你推荐几本超级实用的书籍...
安卓系统看到的炸弹,技术解析与... 安卓系统看到的炸弹——揭秘手机中的隐形威胁在数字化时代,智能手机已经成为我们生活中不可或缺的一部分。...
鸿蒙系统有安卓文件,畅享多平台... 你知道吗?最近在科技圈里,有个大新闻可是闹得沸沸扬扬的,那就是鸿蒙系统竟然有了安卓文件!是不是觉得有...
宝马安卓车机系统切换,驾驭未来... 你有没有发现,现在的汽车越来越智能了?尤其是那些豪华品牌,比如宝马,它们的内饰里那个大屏幕,简直就像...
p30退回安卓系统 你有没有听说最近P30的用户们都在忙活一件大事?没错,就是他们的手机要退回安卓系统啦!这可不是一个简...
oppoa57安卓原生系统,原... 你有没有发现,最近OPPO A57这款手机在安卓原生系统上的表现真是让人眼前一亮呢?今天,就让我带你...
安卓系统输入法联想,安卓系统输... 你有没有发现,手机上的输入法真的是个神奇的小助手呢?尤其是安卓系统的输入法,简直就是智能生活的点睛之...
怎么进入安卓刷机系统,安卓刷机... 亲爱的手机控们,你是否曾对安卓手机的刷机系统充满好奇?想要解锁手机潜能,体验全新的系统魅力?别急,今...
安卓系统程序有病毒 你知道吗?在这个数字化时代,手机已经成了我们生活中不可或缺的好伙伴。但是,你知道吗?即使是安卓系统,...
奥迪中控安卓系统下载,畅享智能... 你有没有发现,现在汽车的中控系统越来越智能了?尤其是奥迪这种豪华品牌,他们的中控系统简直就是科技与艺...