tnblog
首页
视频
资源
登录

.net Source Generators的基本使用

1631人阅读 2024/9/25 16:12 总访问:3455562 评论:0 收藏:0 手机
分类: .net后台框架

.netcore

.net Source Generators的基本使用

Source Generators简介


Source Generators是一项C#编译功能,使C#开发人员能够在编译用户代码时进行检查,并动态生成新的C#源文件,以添加到用户的编译中。
通过这种方式,你的代码可以在编译过程中运行并检查你的程序以生成与其余代码一起编译的其他源文件。

允许执行两个主要操作


1.检索表示正在编译的所有用户代码的编译对象。可以检查此对象,并且可以编写适用于正在编译的代码语法和语义模型的代码,就像现在使用分析器一样。
2.生成可在编译过程中添加到编译对象的C#源文件。也就是说,在编译代码时,可以提供其他源代码作为编译的输入。

简单示例


首先创建一个LearningSourceGenerators使用.net8的控制台项目。
然后安装Microsoft.CodeAnalysis.AnalyzersMicrosoft.CodeAnalysis.CSharp两个包。

  1. <ItemGroup>
  2. <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
  3. <PrivateAssets>all</PrivateAssets>
  4. <!--<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>-->
  5. </PackageReference>
  6. <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" PrivateAssets="all" />
  7. </ItemGroup>


将 Program 类替换为以下代码。

  1. namespace LearningSourceGenerators;
  2. partial class Program
  3. {
  4. static void Main(string[] args)
  5. {
  6. HelloFrom("Generated Code");
  7. }
  8. static partial void HelloFrom(string name);
  9. }


然后创建一个LearningSourceGenerators.Tools的项目,框架版本为.NET Standard 2.0
同样需要安装Microsoft.CodeAnalysis.AnalyzersMicrosoft.CodeAnalysis.CSharp两个包。需要添加上PrivateAssets="all"

目前 .NET Standard 2.0 程序集只能用作源生成器。


创建一个名为HelloSourceGenerator.cs的新 C# 文件,该文件指定你自己的源生成器。
并添加以下内容:

  1. [Generator]
  2. public class HelloSourceGenerator : ISourceGenerator
  3. {
  4. public void Execute(GeneratorExecutionContext context)
  5. {
  6. // Find the main method
  7. var mainMethod = context.Compilation.GetEntryPoint(context.CancellationToken);
  8. // Build up the source code
  9. string source = $@"// <auto-generated/>
  10. using System;
  11. namespace {mainMethod.ContainingNamespace.ToDisplayString()}
  12. {{
  13. public static partial class {mainMethod.ContainingType.Name}
  14. {{
  15. static partial void HelloFrom(string name) =>
  16. Console.WriteLine($""Generator says: Hi from '{{name}}'"");
  17. }}
  18. }}
  19. ";
  20. var typeName = mainMethod.ContainingType.Name;
  21. // Add the source code to the compilation
  22. context.AddSource($"{typeName}.g.cs", source);
  23. }
  24. public void Initialize(GeneratorInitializationContext context)
  25. {
  26. }
  27. }


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

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


然后我们添加LearningSourceGenerators.Tools项目到我们的LearningSourceGenerators控制台项目中。

  1. <ItemGroup>
  2. <ProjectReference Include="..\LearningSourceGenerators.Tools\LearningSourceGenerators.Tools.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
  3. </ItemGroup>


须手动编辑以包含 OutputItemTypeReferenceOutputAssembly 属性。
OutputItemType="Analyzer":表示引用项目的输出是一个Roslyn编译器分析器,而不是普通的项目依赖项。
ReferenceOutputAssembly="false":表示该项目不会编译到当前项目的输出程序集中。
接下来我们开始运行程序。


程序执行完成,输出了相关内容。
我们在调试的时候发现它生成的代码文件在C盘下面。
如何将它源代码保存到本地呢?

源代码保存到本地


可以通过在LearningSourceGenerators.csproj中设置EmitCompilerGeneratedFiles属性完成。

  1. <PropertyGroup>
  2. <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
  3. </PropertyGroup>


完成此配置之后,将会自动将源代码生成器所生成的代码存放到本地文件夹里面。
调试下的输出大概是 obj\Debug\net8.0\ 等类似的文件夹里。


如果期望自己指定保存的文件夹,可以自行设置 EmitCompilerGeneratedFiles 属性,如以下代码:

  1. <PropertyGroup>
  2. <CompilerGeneratedFilesOutputPath>Generated\$(TargetFramework)</CompilerGeneratedFilesOutputPath>
  3. </PropertyGroup>


以上代码之所以拼接上 TargetFramework 是因为期望默认处理多框架的文件冲突问题,源代码生成器会在多框架下分别执行,为每个框架生成独立的代码。如果在多框架项目下没有配置加上 TargetFramework 将会造成生成的源代码存放的文件冲突
上面代码添加之后,预计将会导致构建不通过,一般的保存信息如下


这是因为设置放在 Generated\$(TargetFramework) 会被 csproj 默认作为源代码引用,导致原本源代码生成器生成的代码已经在内存里面被引用一次,现在源代码生成器输出的文件又被再次引用,导致了最终构建不通过
解决方法就是去掉对 CompilerGeneratedFilesOutputPath 的文件的引用,确保只有引用源代码生成器在内存的一份代码,如以下代码:

  1. <ItemGroup>
  2. <!-- 添加了内存里面的文件,不应该添加磁盘的,否则添加两份 -->
  3. <Compile Remove="$(CompilerGeneratedFilesOutputPath)/**/*.cs" />
  4. </ItemGroup>

发布NuGet Package


从源生成器创建NuGet包类似于标准库的NuGet包,但NuGet包的内容布局不同。具体来说,您必须:
+ 确保生成输出最终位于 NuGet 包的 analyzers/dotnet/cs 文件夹中。
+ 确保dll不会出现在NuGet包的normal文件夹中。
对于第一点,请确保你的项目中有以下内容:

  1. <ItemGroup>
  2. <None Include="$(OutputPath)\$(AssemblyName).dll" Pack="true" PackagePath="analyzers/dotnet/cs" Visible="false" />
  3. </ItemGroup>


这将确保源生成器程序集打包到NuGet包中的正确位置,以便编译器将其作为分析器/源生成器加载。
你还应该将该属性设置为,以便使用项目不会获得对源生成器dll本身的引用:

  1. <PropertyGroup>
  2. <IncludeBuildOutput>false</IncludeBuildOutput>
  3. </PropertyGroup>


开始打包:


然后创建一个LearningSourceGenerators.TestConsole新的项目,并且在本地添加上源然后安装好这个包。


添加代码。

  1. namespace LearningSourceGenerators.TestConsole;
  2. partial class Program
  3. {
  4. static void Main(string[] args)
  5. {
  6. HelloFrom("Generated Code");
  7. }
  8. static partial void HelloFrom(string name);
  9. }


然后我们也能看见代码生成器那儿已经生成好了代码。


欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739

评价

tomcat 的基本使用

一、在webapps文件夹下创建一个自己的文件夹二、在自己的文件夹下面放入自己的资源资源类容三、访问(路径为8080+自己的文...

HTTPSession 的基本使用 1

一、常用方法二、获取三、使用1、创建web项目与功能类2-4、另一个功能类5-6、a、b、

Kustomize的基本使用

Kustomize的基本使用[TOC] 什么是 Kustomize?Kustomize允许您自定义原始的、无模板的 YAML 文件以用于多种用途,而原始 Y...

.net Roslyn的基本使用

.net Roslyn的基本使用[TOC] Roslyn简介Roslyn是C#和Visual Basic编译器的开源实现,具有用于构建代码分析工具的API表面。...

剪映的基本使用。音频如何删除,音频如何删除某一部分,如何修改某张图片的播放时间

默认一张图片只有三秒钟的时间如果不够的话可以拖动修改时间。 音频如何删除?单击选中后下面就有删除选项了。 音频如何...

net core 使用 EF Code First

下面这些内容很老了看这篇:https://www.tnblog.net/aojiancc2/article/details/5365 项目使用多层,把数据库访问...

cAPS.net 保存base64位格式的图片

publicvoidUpload() { //取出图片对应的base64位字符 stringimgBase=Request[&quot;imgBase&quot;]; //c#里边的base6...

Quartz.net实例动态改变周期调度。misfire、Cron

Quartz:Java编写的开源的任务调度作业框架 类似Timer之类定时执行的功能,但是更强大Quartz.NET:是把Quartz转成C# NuGet...

.net Windows服务发布、安装、卸载、监听脚本。服务调试

一、脚本 为方便不用每次都去写安装卸载的脚本1.安装脚本@echooff @echo开始安装【服务】 %SystemRoot%\Microsoft.NET\Fr...

c、VB.net中全角半角转换方法

///&lt;summary&gt; ///转全角的函数(SBCcase) ///&lt;/summary&gt; ///&lt;paramname=&quot;input&quot;&gt;任意字符串...

.net mvc分部页,.net core分部页

.net分部页的三种方式第一种:@Html.Partial(&quot;_分部页&quot;)第二种:@{ Html.RenderPartial(&quot;分部页&quot;);}...

C.net 配合小程序实现经过第三方服务器中转文件

某些时候,微信小程序前段上传文件的时候需要经过第三方服务器再将文件上传到客户的服务器;操作如下:1:(小程序内向中端服...

.net实现QQ邮箱发送邮件功能

1、微软已经帮我们封装好了发送邮件的类MailMessage,MailMessage类构造一些邮件信息,然后通过SmtpClient进行邮件发送。Mai...

StackExchange.Redis操作redis(net core支持)

官方git开源地址https://github.com/StackExchange/StackExchange.Redis官方文档在docs里边都是官方的文档通过nuget命令下...

windows 自带的netsh进行端口映射

使用netsh 把本地任意ip的25566端口 映射到192.168.81.234的25565端口netshinterfaceportproxyaddv4tov4listenaddress=0.0....
这一世以无限游戏为使命!
排名
2
文章
633
粉丝
44
评论
93
docker中Sware集群与service
尘叶心繁 : 想学呀!我教你呀
一个bug让程序员走上法庭 索赔金额达400亿日元
叼着奶瓶逛酒吧 : 所以说做程序员也要懂点法律知识
.net core 塑形资源
剑轩 : 收藏收藏
映射AutoMapper
剑轩 : 好是好,这个对效率影响大不大哇,效率高不高
ASP.NET Core 服务注册生命周期
剑轩 : http://www.tnblog.net/aojiancc2/article/details/167
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术