Source Generator初探

Posted 摧残一生 涅槃重生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Source Generator初探相关的知识,希望对你有一定的参考价值。

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执行无法达到效果,还未找到原因

以上是关于Source Generator初探的主要内容,如果未能解决你的问题,请参考以下文章

Source Generator-扩充原有代码

Source Generator 单元测试

Source Generator-添加诊断

.NET 6 中的 Logging Source Generator

C# 强大的新特性 Source Generator

可以物理访问 Source Generator 创建的文件吗?