在上一篇部落格告訴大家如何在 IIncrementalGenerator 增量 Source Generator 裡讀取 csproj 專案檔案的屬性配置,詳細請看:
IIncrementalGenerator 增量 Source Generator 生成程式碼入門 讀取 csproj 專案檔案的屬性配置
在上一篇部落格裡面,核心是透過配置了 CompilerVisibleProperty
讓屬性可見,如下面程式碼所示
<PropertyGroup>
<MyCustomProperty>lindexi is doubi</MyCustomProperty>
</PropertyGroup>
<ItemGroup>
<CompilerVisibleProperty Include="MyCustomProperty" />
</ItemGroup>
在分析器裡面獲取屬性內容的核心程式碼如下
context.RegisterImplementationSourceOutput(context.AnalyzerConfigOptionsProvider,
(productionContext, provider) =>
{
var text = string.Empty;
// 透過 csproj 等 PropertyGroup 裡面獲取
// 需要將可見的,放入到 CompilerVisibleProperty 裡面
// 需要加上 `build_property.` 字首
if (provider.GlobalOptions.TryGetValue("build_property.MyCustomProperty", out var myCustomProperty))
{
text += " " + myCustomProperty;
}
});
本文將告訴大家如何獲取引用檔案的 ItemGroup 裡面的 Item 的 Metadata 內容如何獲取到。如下面專案檔案的程式碼,定義了名為 PaintStateDiagramMarkdownFile 的 Item 項,此項裡面包含了 Link 這個 Metadata 內容
<ItemGroup>
<PaintStateDiagramMarkdownFile Include="..\KereqeewahaihibayNohelqiji\*.txt" Link="Assets\StateDiagrams\%(RecursiveDir)%(Filename)%(Extension)" />
</ItemGroup>
如期望讓其 PaintStateDiagramMarkdownFile
項在分析器可見,需要將其新增到 AdditionalFiles 裡面,如下面程式碼
<ItemGroup>
<AdditionalFiles Include="@(PaintStateDiagramMarkdownFile)"/>
</ItemGroup>
為了讓 Link 這個 Metadata 內容同樣被分析器可見,需要在將 PaintStateDiagramMarkdownFile 新增到 AdditionalFiles 時,附帶將 Link 帶上,更新之後的程式碼如下
<ItemGroup>
<AdditionalFiles Include="@(PaintStateDiagramMarkdownFile)" Link="%(Link)"/>
</ItemGroup>
再使用 CompilerVisibleItemMetadata 設定 AdditionalFiles 的 Link 也是對分析器可見,程式碼如下
<ItemGroup>
<CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="Link" />
</ItemGroup>
如此即可在後續分析器裡面裡面使用 AnalyzerConfigOptionsProvider 的 GetOptions 方法獲取到 Metadata 資訊
以上編輯之後的 csproj 專案檔案內容如下
<ItemGroup>
<PaintStateDiagramMarkdownFile Include="..\KereqeewahaihibayNohelqiji\*.txt" Link="Assets\StateDiagrams\%(RecursiveDir)%(Filename)%(Extension)" />
<AdditionalFiles Include="@(PaintStateDiagramMarkdownFile)" Link="%(Link)"/>
<CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="Link" />
</ItemGroup>
當然了,在真正的 NuGet 打包專案上,常常會將 AdditionalFiles 和 CompilerVisibleItemMetadata 寫到 target 或 props 檔案裡面,而不是放在 csproj 裡面。詳細請參閱我的 部落格導航 獲取分析器入門知識
在分析器裡面裡面,可先收集或用其他方式獲取到 AdditionalFiles 內容,將其傳入給到 AnalyzerConfigOptionsProvider 的 GetOptions 方法,即可獲取到 AnalyzerConfigOptions 物件。再對 AnalyzerConfigOptions 呼叫 TryGetValue 方法,傳入字串格式是 build_metadata.AdditionalFiles.[MetadataName]
即可獲取到 Metadata 資訊。以上字串格式的 [MetadataName]
還請替換為實際需要獲取的值,如本文以上例子裡面期望獲取到 Link 這個 Metadata 內容,可使用如下程式碼
AnalyzerConfigOptionsProvider analyzerConfigOptionsProvider = ...
AdditionalText additionalText = ...
AnalyzerConfigOptions analyzerConfigOptions = analyzerConfigOptionsProvider.GetOptions(additionalText);
if (analyzerConfigOptions.TryGetValue("build_metadata.AdditionalFiles.Link", out var link))
{
}
為了更好的說明使用方法,我建立了兩個專案,其中一個專案是分析器專案,另一個是控制檯專案。我將演示如何獲取控制檯專案所配置的 PaintStateDiagramMarkdownFile 項的 Link 資訊。本文內容裡面只給出關鍵程式碼片段,如需要全部的專案檔案,可到本文末尾找到本文所有程式碼的下載方法
以下是控制檯專案 CujelcijallChearjawjuja 的 csproj 檔案的程式碼
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PaintStateDiagramMarkdownFile Include="..\KereqeewahaihibayNohelqiji\*.txt" Link="Assets\StateDiagrams\%(RecursiveDir)%(Filename)%(Extension)" />
<None Include="@(PaintStateDiagramMarkdownFile)"></None>
<AdditionalFiles Include="@(PaintStateDiagramMarkdownFile)" Link="%(Link)"/>
<CompilerVisibleItemMetadata Include="AdditionalFiles" MetadataName="Link" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\KereqeewahaihibayNohelqiji\KereqeewahaihibayNohelqiji.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
</ItemGroup>
</Project>
可以看到寫了 PaintStateDiagramMarkdownFile 項,且將其新增到 AdditionalFiles 裡面,新增的過程中還將 PaintStateDiagramMarkdownFile 的 Link 賦值給到 AdditionalFiles 的 Link 裡
最後配置 CompilerVisibleItemMetadata 讓 AdditionalFiles 的 Link 資訊被分析器可見
中間新增的 <None Include="@(PaintStateDiagramMarkdownFile)"></None>
只是一個簡單的除錯程式碼,用於讓我可以在 VisualStudio 專案裡面看到檔案而已,和本文實際的演示沒有關係
新增分析器 KereqeewahaihibayNohelqiji 專案,分析器專案的 csproj 專案檔案的程式碼如下
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.11.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.10.0" PrivateAssets="all" />
</ItemGroup>
</Project>
以上程式碼的 EnforceExtendedAnalyzerRules 屬性含義請參閱 Roslyn 分析器 EnforceExtendedAnalyzerRules 屬性的作用
在 KereqeewahaihibayNohelqiji 專案放入 TextFile.txt 檔案用於給 CujelcijallChearjawjuja 專案引用
在 KereqeewahaihibayNohelqiji 編寫名為 YelgahainaljinalBehoballdewur 的 IIncrementalGenerator 增量 Source Generator 生成器,程式碼如下
namespace KereqeewahaihibayNohelqiji
{
[Generator(LanguageNames.CSharp)]
internal class YelgahainaljinalBehoballdewur : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
// 在這裡編寫程式碼
context.RegisterImplementationSourceOutput(context.AdditionalTextsProvider.Collect().Combine(context.AnalyzerConfigOptionsProvider),
(productionContext, provider) =>
{
// 這裡的程式碼只有當配置初始化或變更時才會被執行
var additionalTextArray = provider.Left;
AnalyzerConfigOptionsProvider analyzerConfigOptionsProvider = provider.Right;
var stringBuilder = new StringBuilder();
for (int i = 0; i < 3; i++)
{
stringBuilder.Append('"');
}
stringBuilder.AppendLine();
foreach (AdditionalText additionalText in additionalTextArray)
{
AnalyzerConfigOptions analyzerConfigOptions = analyzerConfigOptionsProvider.GetOptions(additionalText);
if (analyzerConfigOptions.TryGetValue("build_metadata.AdditionalFiles.Link", out var link))
{
stringBuilder.AppendLine($"File={additionalText.Path}");
stringBuilder.AppendLine($"Link={link}");
}
}
for (int i = 0; i < 3; i++)
{
stringBuilder.Append('"');
}
var code = @"using System;
namespace CujelcijallChearjawjuja
{
public static class Foo
{
public static void F1()
{
Console.WriteLine(" + stringBuilder.ToString() + @");
}
}
}";
productionContext.AddSource("Foo.cs", code);
});
}
}
}
如此期望能夠將控制檯專案裡面的 PaintStateDiagramMarkdownFile 作為 Foo 型別的 F1 方法輸出控制檯資訊的內容
編輯控制檯專案 CujelcijallChearjawjuja 的 Program.cs 檔案,新增如下程式碼
using CujelcijallChearjawjuja;
Foo.F1();
執行控制檯專案,大概可以看到如下輸出內容。如此可以證明此方法可以獲取 Item 項裡面配置的 Metadata 資訊
File=C:\lindexi\Workbench\CujelcijallChearjawjuja\..\KereqeewahaihibayNohelqiji\TextFile.txt
Link=Assets\StateDiagrams\TextFile.txt
本文程式碼放在 github 和 gitee 上,可以使用如下命令列拉取程式碼。我整個程式碼倉庫比較龐大,使用以下命令列可以進行部分拉取,拉取速度比較快
先建立一個空資料夾,接著使用命令列 cd 命令進入此空資料夾,在命令列裡面輸入以下程式碼,即可獲取到本文的程式碼
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin eb119d9e64e387cea847aee79f4509744c349018
以上使用的是國內的 gitee 的源,如果 gitee 不能訪問,請替換為 github 的源。請在命令列繼續輸入以下程式碼,將 gitee 源換成 github 源進行拉取程式碼。如果依然拉取不到程式碼,可以發郵件向我要程式碼
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin eb119d9e64e387cea847aee79f4509744c349018
獲取程式碼之後,進入 Workbench/CujelcijallChearjawjuja 資料夾,即可獲取到原始碼
更多分析器和原始碼生成部落格,請參閱 部落格導航