.NET初探源代码生成(Source Generators)

不管现实多么惨不忍睹,都要持之以恒地相信,这只是黎明前短暂的黑暗而已。不要惶恐眼前的难关迈不过去,不要担心此刻的付出没有回报,别再花时间等待天降好运。真诚做人,努力做事!你想要的,岁月都会给你。.NET初探源代码生成(Source Generators),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

前言

Source Generators顾名思义代码生成器,可进行创建编译时代码,也就是所谓的编译时元编程,这可让一些运行时映射的代码改为编译时,同样也加快了速度,我们可避免那种昂贵的开销,这是有价值的。

实现ISourceGenerator

集成ISourceGenerator接口,实现接口用于代码生成策略,它的生命周期由编译器控制,它可以在编译时创建时创建并且添加到编译中的代码,它为我们提供了编译时元编程,从而使我们对C#代码或者非C#源文件进行内部的检查。

    [Generator]
    class CustomGenerator: ISourceGenerator
    {
        public void Initialize(GeneratorInitializationContext context)
        {
            throw new NotImplementedException();
        }

        public void Execute(GeneratorExecutionContext context)
        {
            throw new NotImplementedException();
        }
    }
 public void Execute(GeneratorExecutionContext context)
{
    var compilation = context.Compilation;
    var simpleCustomInterfaceSymbol = compilation.GetTypeByMetadataName("SourceGeneratorDemo.ICustom");

    const string code = @"
using System;
namespace SourceGeneratorDemo
{   
    public partial class Program{
             public static void Display(){
             Console.WriteLine(""Hello World!"");
            }
    }
}";

            if (!(context.SyntaxReceiver is CustomSyntaxReceiver receiver))
                return;
            //语法树可参考Roslyn Docs
            SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);

            //context.AddSource("a.class", code);
            context.AddSource("a.class", SourceText.From(text: code, encoding: Encoding.UTF8));

            //https://github.com/gfoidl-Tests/SourceGeneratorTest
            {
                StringBuilder sb = new();
                sb.Append(@"using System;
using System.Runtime.CompilerServices;
#nullable enable
[CompilerGenerated]
public static class ExportDumper
{
    public static void Dump()
    {");
                foreach (BaseTypeDeclarationSyntax tds in receiver.Syntaxes)
                {
                    sb.Append($@"
        Console.WriteLine(""type: {GetType(tds)}\tname: {tds.Identifier}\tfile: {Path.GetFileName(tds.SyntaxTree.FilePath)}"");");
                }
                sb.AppendLine(@"
    }
}");

                SourceText sourceText = SourceText.From(sb.ToString(), Encoding.UTF8);
                context.AddSource("DumpExports.generated", sourceText);

                static string GetType(BaseTypeDeclarationSyntax tds) => tds switch
                {
                    ClassDeclarationSyntax => "class",
                    RecordDeclarationSyntax => "record",
                    StructDeclarationSyntax => "struct",
                    _ => "-"
                };
            }
        }

context.AddSource字符串形式的源码添加到编译中,SourceText原文本抽象类,SourceText.From静态方法,Code指定要创建的源码内容,Encoding设置保存的编码格式,默认为UTF8,context.SyntaxReceiver可以获取在初始化期间注册的ISyntaxReceiver,获取创建的实例

实现ISyntaxReceiver

ISyntaxReceiver接口作为一个语法收集器的定义,可实现该接口,通过对该接口的实现,可过滤生成器所需

public class CustomSyntaxReceiver : ISyntaxReceiver
{
    public List<BaseTypeDeclarationSyntax> Syntaxes { get; } = new();

    /// <summary>
    ///     访问语法树
    /// </summary>
    /// <param name="syntaxNode"></param>
    public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
    {
        if (syntaxNode is BaseTypeDeclarationSyntax cds)
        {
            Syntaxes.Add(cds);
        }
    }
}

可以再此处进行过滤,如通过ClassDeclarationSyntax过滤Class类,当然也可以改为BaseTypeDeclarationSyntax,或者也可以使用InterfaceDeclarationSyntax添加接口类等等

调试

对于Source Generator可以通过添加Debugger.Launch()的形式进行对编译时的生成器进行调试,可以通过它很便捷的一步步调试代码.

 public void Initialize(GeneratorInitializationContext context)
        {
            Debugger.Launch();
            ......
        }

Library&Properties

 <ItemGroup>
    <ProjectReference Include="..\ClassLibrary1\ClassLibrary1.csproj"
                      OutputItemType="Analyzer"
                      ReferenceOutputAssembly="false" />
  </ItemGroup>
  • ReferenceOutputAssembly:如果设置为false,则不包括引用项目的输出作为此项目的引用,但仍可确保在此项目之前生成其他项目。 默认为 true。
  • OutputItemType:可选项,将目标要输出的类型,默认为空,如果引用值设置为true(默认值),那么目标输出将为编译器的引用。

Reference

https://github.com/hueifeng/BlogSample/tree/master/src/SourceGeneratorDemo

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/158510.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!