sourcegenerator初探(代码片段)

摧残一生涅槃重生 摧残一生涅槃重生     2023-03-18     190

关键词:

Source Generator

什么是Source Generator

.NET 5引入的系特性,可在应用编译期间根据当前编译信息动态生成代码,也可以直接引用动态生成的代码。

优势

加快运行速度

原有的程序机制是初次运行时通过反射进行依赖注入,这时会导致第一次运行加载大量数据,运行会慢,再一个不利于AOT编译。

而Source Generator是在编译时完成依赖注入,把之前运行所作的大部分工作都完成,这样即可利于AOT编译,又可以保证运行时的速度。

增加了代码的灵活性

将运行时加载变为了编译时加载,可以让程序在编译时动态加载程序员想要的代码,这些代码可以来源于Xml,JSON等文件,依次类推,我们可以通过维护Xml或者JSON来动态编译实现无代码平台。

解决AOT编译

AOT也是一个新特性,但使用反射的程序无法使用该特性,使用Source Generator可避免AOT特性无法使用的情况。

第一个Source Generator例子

  • 创建一个控制台程序

    1. 选择控制台应用,下一步

    2. 创建项目名称,下一步

    3. 框架选择默认(目前默认的为Net 6.0),并勾选不适用顶级语句,创建项目

    4. 修改Program.cs代码,修改部分如下:

      namespace SourceGeneratorDemo
      
          // internal 改为 partial,否则可见级别太低,使用public的话Program可见级别太高
          partial class Program
          
              static void Main(string[] args)
              
                  Console.WriteLine("Hello, World!");
                  // 添加该行
                  HelloCode("Hello, Code");
              
              // 添加该行 动态编译并调用HelloCode
              static partial void HelloCode(string name);
          
      
      
    5. 此时,直接编译并运行可通过,HelloCode方法未找到会自动跳过

  • 创建netstandard2.0的类库项目

    1. 选择类库项目,下一步

    2. 添加项目名称,下一步

    3. 选择框架(netstandard2.0),创建

    4. 添加Microsoft.CodeAnalysis.Analyzers 和 Microsoft.CodeAnalysis.CSharp依赖,依赖项信息可通过点击项目进行查看

        <ItemGroup>
          <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
            <PrivateAssets>all</PrivateAssets>
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
          </PackageReference>
          <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.5.0" />
        </ItemGroup>
      
    5. 将Class1.cs改名为SourceGeneratorMethod.cs,并添加代码

      [Generator]
      public class HelloSourceGenerator : ISourceGenerator
      
          public void Execute(GeneratorExecutionContext context)
          
              // Find the main method
              var mainMethod = context.Compilation.GetEntryPoint(context.CancellationToken);
      
              // Build up the source code
              string source = $@"// <auto-generated/>
      using System;
      
      namespace mainMethod.ContainingNamespace.ToDisplayString()
      
      public static partial class mainMethod.ContainingType.Name
      
          static partial void HelloCode(string name) =>
              Console.WriteLine($""Generator says: Hi from \'name\'"");
      
      
      ";
              var typeName = mainMethod.ContainingType.Name;
      
              // Add the source code to the compilation
              context.AddSource($"typeName.g.cs", source);
          
      
          public void Initialize(GeneratorInitializationContext context)
          
              // No initialization required for this one
          
      
      
    6. 编译SourceGenerator项目

  • 在控制台中添加对类库的依赖

    1. SourceGeneratorDemo项目中选择依赖项,点击右键添加项目引用,引用类库项目

    2. 双击SourceGeneratorDemo项目,添加OutputItemTypeReferenceOutputAssembly 属性

        <ItemGroup>
          <ProjectReference Include="..\\SourceGenerator\\SourceGenerator.csproj" 
                            OutputItemType="Analyzer"
                            ReferenceOutputAssembly="false" />
        </ItemGroup>
      
    3. 生成SourceGeneratorDemo并运行

    4. 结果,并没有输出Hello, Code

  • 问题解决

    1. 重新打开项目

    2. 将Microsoft.CodeAnalysis.Analyzers 和 Microsoft.CodeAnalysis.CSharp引用修改为如下引用:

        <ItemGroup>
          <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" PrivateAssets="all" />
          <PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.3">
            <PrivateAssets>all</PrivateAssets>
            <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
          </PackageReference>
        </ItemGroup>
      
    3. 清理SourceGenerator和SourceGeneratorDemo项目

    4. 重新运行,出现了Hello,Code

  • 原因判断:

    • 经测试,Microsoft.CodeAnalysis.Analyzers可不使用,只需要引用Microsoft.CodeAnalysis.CSharp即可

      <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.4.0" PrivateAssets="all" />
      
    • Microsoft.CodeAnalysis.CSharp的4.5.0版本和4.6.0-1.final执行无法达到效果,还未找到原因

抽丝剥茧!sourcegenerators原理讲解(代码片段)

前言前段时间,我们已经用SourceGenerators实现了好多功能,比如AutoMapper、API最佳实践。你看完那些实现代码,是不是还有点云里雾里!SourceGenerators到底是怎么做到的?基础知识SourceGenerators是编译过程的一部分&... 查看详情

sourcegenerator单元测试(代码片段)

SourceGenerator单元测试IntroSourceGenerator是.NET5.0以后引入的一个在编译期间动态生成代码的一个机制,介绍可以参考C#强大的新特性SourceGeneratorGetStarted使用起来还算比较简单的,我平时一般用xunit,所以下面的示例也是使... 查看详情

helloblazor:sourcegenerators生成导航菜单(代码片段)

前言最近写了多篇关于SourceGenerators的文章,发现它确实可以简化我们的部分开发工作。这不,我又盯上了Blazor。问题默认的NavMenu.razor组件用于显示导航菜单,它的部分代码如下:<div class="@NavMenuCssClass... 查看详情

sourcegenerator-扩充原有代码(代码片段)

...原有代码中新增方法,扩展我们自己写的代码。这个使用SourceGenerator也可以实现在上一章的接触上新增类库(AugmentingGeneratorMethod)添加Microsoft.CodeAnalysis.Analyzers和Microsoft.CodeAnalysis.CSharp引用:<ItemGroup><PackageReferenceInclude="Mic... 查看详情

sourcegenerators实现简版automapper(代码片段)

问题在业务开发中,我们常常需要将一个对象映射成另一个对象。例如将领域实体(UserEntity)映射成暴露给服务外部使用的数据传输对象(UserDto)。而AutoMapper则是目前主流的解决方案,实现类似如下代码:var configuration ... 查看详情

究竟是什么可以比反射还快实现动态调用?|sourcegenerators版(代码片段)

...使用反射快上10倍的性能。就这一需求来说,我认为SourceGenerators应该会更快,因为访问代码在编译时而不是 查看详情

sourcegenerator-添加诊断(代码片段)

诊断的含义通过自己的逻辑代码判断动态编译的代码是否有问题,有问题时需要告诉编译器有警告或者错误,让编译器返回来向我们展示我们期望的诊断信息。因为动态编译时编译器无法得知我们写入是否有问题,从而产生很多... 查看详情

.netcore开发实战(定义api的最佳实践)sourcegenerators版(代码片段)

前言极客时间上的《.NETCore开发实战》是一门非常好的课程,作者肖伟宇在第31课(https://time.geekbang.org/course/detail/100044601-201165)介绍了定义API的最佳实践。大意如下:Controller这一层负责与前端用户的交互,它... 查看详情

.net性能优化-使用sourcegenerator-logger记录日志(代码片段)

前言在现在许许多多的应用系统中,日志非常关键,它即是排查问题的强力工具,也是程序员居家旅行工作甩锅必备良品。在团队中编码中,我们都要求对于那些会变更数据的接口、调用第三方的接口记录请求和... 查看详情

七:初探异步编程(代码片段)

同步编程创建类usingSystem;usingSystem.Diagnostics;namespaceTestAsyncConsolepublicclassNormalClassStopwatchsw=newStopwatch();publicvoidDoSomething()constintlargeNumber=600000;sw.Start();intt1=CountChar(1,l 查看详情

初探dan(代码片段)

file:///C:/Users/elong/AppData/Local/Temp/MarkdownPadPreview.htmlD:\\users\\elong\\Anaconda3\\envs\\mini27\\python.exeE:/DeepAlignmentNetwork-master/DeepAlignmentNetwork/DANtesting.pyLoadingnetwork... 查看详情

mglearn初探(代码片段)

这个是取自于《python机器学习基础教程》16页代码:#importnumpyasnp#importmatplotlib.pyplotasplt#importpandasaspd#importmglearn#fromsklearn.datasetsimportload_iris#fromsklearn.model_selectionimporttrain_test_split#iris_data 查看详情

rxjava初探(代码片段)

RxJava基础RxJava是什么RxJavaisaJavaVMimplementationofReactiveExtensions:alibraryforcomposingasynchronousandevent-basedprogramsbyusingobservablesequences.RxJava就是一个实现异步操作的库。前言异步操作在调度过程比较复杂的情况下,经常会既难写 查看详情

btrace初探(代码片段)

BTrace是一款java诊断工具,在解决现场问题的时候非常有用。今天使用的时候碰到几个坑,先记录一下.下载下来以后直接运行报错[email protected]:~/btrace-bin-1.3.11/bin#./btrace6582/root/testBtrace.javaExceptioninthread"main"java.lang.NoClassDefFoundError:... 查看详情

hilt初探(代码片段)

Hilt初探Hilt就是Android团队联系了Dagger2团队,一起开发出来的一个专门面向Android的依赖注入框架。相比于Dagger2,Hilt最明显的特征就是:1.简单。2.提供了Android专属的API。Hilt做的优化包括无需编写大量的Component代码Scope... 查看详情

ecc初探(代码片段)

为了学习一下ECC加密,练习了unctf2019的一道题目,不算难但是可以很好的学习一下ECC加密的流程,题目主要是AES+ECC,但是重点还是ECC的加密。下载文件后我们得到一个ecc.sageE=EllipticCurve(GF(15424654874903),[16546484,4548674875])G=E(6478678675,56363793... 查看详情

c++类模板初探(代码片段)

1#include<iostream>23#include<string>45usingnamespacestd;67//你提交的代码将嵌入到这里89constintSIZE=100;1011template<classT>1213classQueue1415Tq[SIZE];1617intfront;//队列头1819intrear;//队列尾2021pub 查看详情

初探装饰器模式(代码片段)

装饰器模式:动态地将责任附加到对象上,允许用户向现有对象添加新功能而不改变其结构。若要扩展功能,装饰器提供了比继承更有弹性的替代方案。场景:假如有这样一个抽象装备类packagepattern.decorator;publicabstractclassEquipmenti... 查看详情