Source Generator:C# 9 将迎来编译时元编程
源碼生成器(Source Generator)是 C#編譯器的一個新特性,開發者可以使用編譯器生成的元數據檢查用戶代碼,并生成附加的源文件,與程序的其他部分一起編譯。
受 F#類型提供程序的啟發,C#源碼生成器的目標也是為了啟用元編程,只是以一種完全不同的方式。實際上,F#類型提供程序在內存中觸發類型、屬性和方法,而源碼生成器是將 C#代碼重新加入編譯過程。
源碼生成器不能修改已有代碼,只能向編譯添加新代碼。源碼生成器的另一個限制是它不對其他源碼生成器生成的代碼起作用。這樣可以確保每個代碼生成器將看到相同的編譯輸入,而不管應用程序的順序是怎樣的。有趣的是,源碼生成器并不局限于檢查源代碼及其相關的元數據,它們還可以訪問其他文件。
具體來說,源碼生成器并不是代碼重寫工具,比如優化器或代碼注入器,也不是用來創建新的語言特性的,盡管這在技術上來說是可行的。源碼生成器的使用場景包括自動接口實現、數據序列化,等等。在源碼生成器指南中可以找到更多應用場景,其中還包含了討論內容。
源碼生成器與 Roslyn 代碼分析器有很大的關系,這從它的接口定義可以很明顯地看出來:
namespace Microsoft.CodeAnalysis {public interface ISourceGenerator{void Initialize(InitializationContext context);void Execute(SourceGeneratorContext context);} }編譯器調用 Initialize 方法,生成器注冊一些稍后將會調用的回調函數。代碼生成發生在 Execute 方法里,它的參數是一個 SourceGeneratorContext 對象,該對象提供對當前 Compilation 對象的訪問。
namespace Microsoft.CodeAnalysis {public readonly struct SourceGeneratorContext{public ImmutableArray<AdditionalText> AdditionalFiles { get; }public CancellationToken CancellationToken { get; }public Compilation Compilation { get; }public ISyntaxReceiver? SyntaxReceiver { get; }public void ReportDiagnostic(Diagnostic diagnostic) { throw new NotImplementedException(); }public void AddSource(string fileNameHint, SourceText sourceText) { throw new NotImplementedException(); }} }可以修改 SourceGeneratorContext 對象,使用 AddSource 來包含其他代碼。正如上面提到的,源碼生成器不僅限于 C#文件。這從 AdditionalFiles 就可以看出來,它支持傳給編譯器的任意文件。
綜上所述,要為“hello world”程序定義一個普通的源碼生成器可以這樣:
using System; using System.Collections.Generic; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Text;namespace SourceGeneratorSamples {[Generator]public class HelloWorldGenerator : ISourceGenerator{public void Execute(SourceGeneratorContext context){// begin creating the source we'll inject into the users compilationvar sourceBuilder = new StringBuilder(@" using System; namespace HelloWorldGenerated {public static class HelloWorld{public static void SayHello() {Console.WriteLine(""Hello from generated code!"");Console.WriteLine(""The following syntax trees existed in the compilation that created this program:""); ");// using the context, get a list of syntax trees in the users compilationvar syntaxTrees = context.Compilation.SyntaxTrees;// add the filepath of each tree to the class we're buildingforeach (SyntaxTree tree in syntaxTrees){sourceBuilder.AppendLine($@"Console.WriteLine(@"" - {tree.FilePath}"");");}// finish creating the source to injectsourceBuilder.Append(@"}} }");// inject the created source into the users compilationcontext.AddSource("helloWorldGenerator", SourceText.From(sourceBuilder.ToString(), Encoding.UTF8));}public void Initialize(InitializationContext context){// No initialization required for this one}} }微軟已經發布了更多的介紹性示例,向開發人員展示如何使用這個新特性。
源代碼生成器可在.NET 5 預覽版和最新的 Visual Studio 預覽版中使用。這個特性仍然處于早期階段,它的 API 和特性可能會在將來的版本中發生變化。
總結
以上是生活随笔為你收集整理的Source Generator:C# 9 将迎来编译时元编程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 记一次排查线上程序内存的忽高忽低,又是大
- 下一篇: 一文解读使用WinDbg排查iis 中C