建设网站要什么电脑,搭建wordpress环境搭建,网站做优化一开始怎么做,二次开发什么意思本文概述了 .NET Compiler Platform#xff08;“Roslyn”#xff09;SDK 附带的源生成器。 通过源生成器#xff0c;C# 开发人员可以在编译用户代码时检查用户代码。 生成器可以动态创建新的 C# 源文件#xff0c;这些文件将添加到用户的编译中。 这样#xff0c;代码可以…本文概述了 .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
Project SdkMicrosoft.NET.SdkPropertyGroupTargetFrameworknetstandard2.0/TargetFramework/PropertyGroupItemGroupPackageReference IncludeMicrosoft.CodeAnalysis.CSharp Version4.4.0 PrivateAssetsall /PackageReference IncludeMicrosoft.CodeAnalysis.Analyzers Version3.3.3PrivateAssetsall/PrivateAssetsIncludeAssetsruntime; build; native; contentfiles; analyzers; buildtransitive/IncludeAssets/PackageReference/ItemGroup/Project创建一个名为 HelloSourceGenerator.cs 的新 C# 文件该文件指定你自己的源生成器如下所示
using Microsoft.CodeAnalysis;namespace ClassLibrary1
{/// summary/// Hello源生成/// /summary[Generator]public class HelloSourceGenerator : ISourceGenerator{/// summary/// 执行代码生成/// /summary/// param namecontext/parampublic void Execute(GeneratorExecutionContext context){//代码生成在此处进行}/// summary/// 初始化/// /summary/// param namecontext/parampublic void Initialize(GeneratorInitializationContext context){//此操作不需要初始化}}
}
源生成器需要同时实现 Microsoft.CodeAnalysis.ISourceGenerator 接口并且具有 Microsoft.CodeAnalysis.GeneratorAttribute。 并非所有源生成器都需要初始化本示例实现就是这种情况其中 ISourceGenerator.Initialize 为空。 将 ISourceGenerator.Execute 方法的内容替换为以下实现
using Microsoft.CodeAnalysis;namespace ClassLibrary1
{/// summary/// Hello源生成/// /summary[Generator]public class HelloSourceGenerator : ISourceGenerator{/// summary/// 执行代码生成/// /summary/// param namecontext/parampublic void Execute(GeneratorExecutionContext context){//代码生成在此处进行//查找主方法var mainMethod context.Compilation.GetEntryPoint(context.CancellationToken);// 编译源代码string source $// auto-generated/
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);}/// summary/// 初始化/// /summary/// param namecontext/parampublic 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 项目中的路径
Project SdkMicrosoft.NET.SdkPropertyGroupOutputTypeExe/OutputTypeTargetFrameworknet6.0/TargetFrameworkImplicitUsingsenable/ImplicitUsingsNullableenable/Nullable/PropertyGroup!-- 将其添加为新的ItemGroup并适当替换路径和名称 --ItemGroupProjectReference Include..\ClassLibrary1.csprojOutputItemTypeAnalyzerReferenceOutputAssemblyfalse //ItemGroup
/Project 控制台项目也需要安装相应的包 新引用不是传统的项目引用必须手动编辑以包含 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 下创建的。 路径的组成部分映射到生成器的生成配置、目标框架、源生成器项目名称和完全限定的类型名称。 可以通过将 元素添加到应用程序的项目文件来选择较方便的输出文件夹。
调试代码 重新生成就会触发调试
直接打包引用是没有效果的修改类库的项目文件
ItemGroupNone Include$(OutputPath)\$(AssemblyName).dll Packtrue PackagePathanalyzers/dotnet/cs Visiblefalse//ItemGroupPropertyGroupIncludeBuiltProjectOutputGroupfalse/IncludeBuiltProjectOutputGroup/PropertyGroup重新打包新建项目引用
学习地址 https://github.com/TimChen44/CC.CodeGenerator