[C#]VS2022を使用したSource Generator入門
C#には Source Generator というメタプログラミング機能があります。
簡単に言えば、
- コンパイルが実行される前(人間がコーディングをしている最中)に
- Source Generator がC#のソースコードを勝手に書いてくれる
という機能です。
メタプログラミングという性質上、万人が使う機能ではありません。初学者向けの情報は非常に少ないと思います。
さらに通常とは異なる開発環境も必要と来たもんだ。
これでは「開発」というスタートラインに立つのが非常に難しい、と思います。(参考:スタート地点に立とうと藻掻いた形跡はこちら)
そこで理屈抜きで「こうしたら開発環境ができるよ」という手順だけをお届けします。
(なぜこうする必要があるのかについては本記事では説明しません。あしからず)
また、2023年12月現在の情報であることにも留意ください。今後変わる可能性は高いです。
.NET Compiler SDK のインストール
Visual Studio Installer を使用して「.NET Compiler SDK」をインストールしてください。
大体の人は同SDKをインストールしていないはずです。(普通は要らないからしょうがない)
新規プロジェクトの作成
クラスライブラリを「.net standard 2.0」で新規作成してください。
.NET6とか.NET8とかは使用できません。必ず「.net standard 2.0」を選択してください。
csprojの上書き
プロジェクトを作成したら、プロジェクトファイルを開き、以下の内容で上書きしてください。
変更前
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
</Project>
変更後
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<LangVersion>12</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<AnalyzerLanguage>cs</AnalyzerLanguage>
<Nullable>enable</Nullable>
<TargetsForTfmSpecificContentInPackage>$(TargetsForTfmSpecificContentInPackage);PackBuildOutputs</TargetsForTfmSpecificContentInPackage>
<IncludeBuildOutput>false</IncludeBuildOutput>
<DevelopmentDependency>true</DevelopmentDependency>
<IncludeSymbols>false</IncludeSymbols>
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
<IsRoslynComponent>true</IsRoslynComponent>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0" PrivateAssets="all" />
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<!-- for nuget publish -->
<Target Name="PackBuildOutputs" DependsOnTargets="SatelliteDllsProjectOutputGroup;DebugSymbolsProjectOutputGroup">
<ItemGroup>
<TfmSpecificPackageFile Include="$(TargetDir)\*.dll" PackagePath="analyzers\dotnet\cs" />
<TfmSpecificPackageFile Include="@(SatelliteDllsProjectOutputGroupOutput->'%(FinalOutputPath)')" PackagePath="analyzers\dotnet\cs\%(SatelliteDllsProjectOutputGroupOutput.Culture)\" />
</ItemGroup>
</Target>
</Project>
IncrementalGeneratorクラスの追加
クラス名は任意です。お好きな名称で記述して下さい。
中身は空でいいです。
using Microsoft.CodeAnalysis;
[Generator(LanguageNames.CSharp)]
public partial class HogeGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
//TODO
}
}
上記のコードを書くとエラー一覧にRS1036警告が出ることがあります。
RS1036 'HogeGenerator': アナライザーまたはソース ジェネレーターを含むプロジェクトでは、プロパティ '<EnforceExtendedAnalyzerRules>true</EnforceExtendedAnalyzerRules>' を指定する必要があります HogeSourceGenerator
警告文を見る限り、csprojに設定をしろと読めるのですが、設定すると動かくなった経験もありますので、気持ちは悪いですが無視して作業を進めてください。
ユニットテストプロジェクトの追加
xUnitなどのテストプロジェクトを追加し、SourceGeneratorプロジェクトを参照してください。なお、テストプロジェクトは.NET6、.NET8を使用して構いません。(テストプロジェクトを .net standard 2.0 にする必要はありまえん)
そして、ユニットテストのcsprojを開き、以下のように加工してください。
変更前(プロジェクト参照のみ抜粋)
<ItemGroup>
<ProjectReference Include="HogeSourceGenerator.csproj" />
</ItemGroup>
変更後
<ItemGroup>
<ProjectReference Include="HogeSourceGenerator.csproj" />
<ProjectReference Include="HogeSourceGenerator.csproj">
<OutputItemType>Analyzer</OutputItemType>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
</ProjectReference>
</ItemGroup>
同じプロジェクトを2回参照していますが、これで合っています。
デバッグプロファイラの追加と選択
デバッグのプロパティをクリックします。場所が分かりづらいので、以下の画像を参考にしてください。
新しいプロファイルを「Roslyn Component」で作成します。
Target Project に先程追加したテストプロジェクトを追加しておきます。
ここまでできたらダイアログを閉じます。
そして、デバッグプロファイラを変更します。
デバッグの開始
あとはHogeGeneratorにブレイクポイントを追加して、デバッグを実行してみましょう。
ブレイクポイントでブレイクが発生すれば環境構築成功です。
ここから先は・・・
ここまでくればスタート地点には立てています。あとは開発をするだけです。
本記事で紹介するのは、ここまでです。
あとは他のサイトを紹介して終わりたいと思います。
環境構築参考サイト
2022年のC# (Incremental) Source Generator開発手法
ものすごい参考になりました。私の記事は上記記事の手順だけを書いたも同然です。
開発方法参考サイト
PrivateProxy
「開発環境参考サイト」でも紹介したneuecc氏作成のOSSです。
同ライブラリについての概要はこちら参照。
.NET 8 UnsafeAccessor を活用したライブラリ PrivateProxy を公開しました
PrivateProxyというライブラリを公開しました。つまるところ、privateフィールド/プロパティ/メソッドにアクセスするライブラリ
上記サイトを読んだ上で、以下のソースコードを読んでください。
これで何をどうしたらいいか、ざっくりわかります。
PrivateProxyのソースコードをDLして、デバッグ実行するのも非常に効果的です。
開発時の注意点
下記は「開発時」特有の注意点です。ライブラリ利用時には、このような現象はありません。
その1
アナライザーに赤丸印が付きますが、気にしないでください。
その2
アナライザーに自動生成されたソースコードが表示されます。このソースコードは以下の特性があります。
- Visual Studio を開くといつの間にか勝手に作成している
- IncrementalGeneratorクラスのコードを変更しても更新はされない
更新したい場合はプロジェクトファイルを一度終了させてから、開き直してください。
Discussion