什么是源生成器
源生成器是由.NET Compiler Platform(“Roslyn”)SDK 附帶。
通過源生成器,C# 開發(fā)人員可以在編譯用戶代碼時檢查用戶代碼。 生成器可以動態(tài)創(chuàng)建新的 C# 源文件,這些文件將添加到用戶的編譯中。 這樣,代碼可以在編譯期間運(yùn)行。 它會檢查你的程序以生成與其余代碼一起編譯的其他源文件。
- 源生成器是 C# 開發(fā)人員可以編寫的一種新組件
源生成器允許執(zhí)行兩個主要操作
1、檢索表示正在編譯的所有用戶代碼的編譯對象。 可以檢查此對象,并且可以編寫適用于正在編譯的代碼的語法和語義模型的代碼,就像現(xiàn)在使用分析器一樣。
2、生成可在編譯過程中添加到編譯對象的 C# 源文件。 也就是說,在編譯代碼時,可以提供其他源代碼作為編譯的輸入。
結(jié)合使用這兩項操作能充分發(fā)揮源生成器的強(qiáng)大功能。 可以使用編譯器在編譯時構(gòu)建的豐富元數(shù)據(jù)檢查用戶代碼。 然后,生成器將 C# 代碼發(fā)送回基于已分析數(shù)據(jù)的同一編譯。 如果你熟悉 Roslyn 分析器,可以將源生成器視為可發(fā)出 C# 源代碼的分析器。
Microsoft 文檔模型圖示
源生成器作為編譯階段運(yùn)行
源生成器是由編譯器與任何分析器一起加載的 .NET Standard 2.0 程序集。 它在可以加載和運(yùn)行 .NET Standard 組件的環(huán)境中使用。
目前只有 .NET Standard 2.0 程序集可以用作源生成器。
常見方案
- 運(yùn)行時反射
- 處理 MSBuild 任務(wù)
- 交織中間語言 (IL)
可用于檢查用戶代碼,并基于當(dāng)今技術(shù)所使用的分析生成信息或代碼。
詳細(xì)內(nèi)容參考Microsoft 文檔
源生成器的使用
1、創(chuàng)建 .NET控制臺應(yīng)用程序
不使用頂級語句, 經(jīng)典格式是必需的
強(qiáng)行使用頂級語句會報:
錯誤 CS0759 沒有為分部方法“Program.HelloFrom(string)”的實現(xiàn)聲明找到定義聲明
方法未聲明的錯誤
namespace SourceCodeConsole
{
public partial class Program
{
static void Main(string[] args)
{
HelloFrom("Generated Code");
}
static partial void HelloFrom(string name);
}
}
2、創(chuàng)建源生成器項目
引入NuGet包:Microsoft.CodeAnalysis.CSharp
Microsoft.CodeAnalysis.Analyzers
繼承 ISourceGenerator 并實現(xiàn)接口方法,也要為實現(xiàn)類添加
[Generator]
特性支持
using Microsoft.CodeAnalysis;
using System.Diagnostics;
namespace HelloSourceCode
{
[Generator]
public class HelloSourceGenerator : ISourceGenerator
{
public void Execute(GeneratorExecutionContext context)
{
// 找到主方法
var mainMethod = context.Compilation.GetEntryPoint(context.CancellationToken);
// 構(gòu)建源代碼
string source = $@"http:// <auto-generated/>
using System;
namespace {mainMethod.ContainingNamespace.ToDisplayString()}
{{
public static partial class {mainMethod.ContainingType.Name}
{{
static partial void HelloFrom(string name) =>
Console.WriteLine($""Generator says: Hi from '{{name}}'"");
}}
}}
";
var typeName = mainMethod.ContainingType.Name;
// 將源代碼添加到編譯中
context.AddSource($"{typeName}.g.cs", source);
}
public void Initialize(GeneratorInitializationContext context)
{
// 不需要初始化
// 附加調(diào)試器進(jìn)程
//if (!Debugger.IsAttached)
//{
// Debugger.Launch();
//}
}
}
}
從
context
對象中,我們可以訪問編譯的入口點(diǎn)或Main
方法。 mainMethod 實例是一個IMethodSymbol
,它表示一個方法或類似方法的符號(包括構(gòu)造函數(shù)、析構(gòu)函數(shù)、運(yùn)算符或?qū)傩?事件訪問器)。Microsoft.CodeAnalysis.Compilation.GetEntryPoint
方法返回程序的入口點(diǎn)的IMethodSymbol
。 其他方法使你可以查找項目中的任何方法符號。 在此對象中,我們可以推理包含的命名空間(如果存在)和類型。 此示例中的source
是一個內(nèi)插字符串,它對要生成的源代碼進(jìn)行模板化,其中內(nèi)插的缺口填充了包含的命名空間和類型信息。 使用提示名稱將source
添加到context
。 對于此示例,生成器創(chuàng)建一個新的生成的源文件,其中包含控制臺應(yīng)用程序中partial
方法的實現(xiàn)。 可以編寫源生成器來添加任何喜歡的源。
GeneratorExecutionContext.AddSource
方法中的hintName
參數(shù)可以是任何唯一名稱。 通常為該名稱提供顯式 C# 文件擴(kuò)展名,例如".g.cs"
或".generated.cs"
。 該文件名有助于將文件標(biāo)識為正在生成源。
關(guān)于
Initialize
方法一般是不用初始化的,上面可以看到我是寫了一段代碼的,作用是進(jìn)入調(diào)試,這樣做的主要原因是,不進(jìn)行附加是無法進(jìn)行調(diào)試的
3、在控制臺程序中使用生成器項目
<ItemGroup>
<ProjectReference Include="..\HelloSourceCode\HelloSourceCode.csproj"
OutputItemType="Analyzer"
ReferenceOutputAssembly="false" />
</ItemGroup>
新引用不是傳統(tǒng)的項目引用,必須手動編輯以包含 OutputItemType 和 ReferenceOutputAssembly 屬性。
-
運(yùn)行結(jié)果
-
查看生成的代碼
文章來源:http://www.zghlxwxcb.cn/news/detail-442531.html
結(jié)語
本文學(xué)術(shù)內(nèi)容皆引用于 Microsoft 文檔
部分詳細(xì)內(nèi)容,本篇不再說明,Microsoft 文檔說得很明確:文檔地址
https://learn.microsoft.com/zh-cn/dotnet/csharp/roslyn-sdk/文章來源地址http://www.zghlxwxcb.cn/news/detail-442531.html
到了這里,關(guān)于C# 源代碼生成器的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!