C#ITUnity

メモ:UnityプロジェクトへのSourceGenerator導入

導入~Unityでのコード生成の基本手順

参考
UnityでSourceGeneratorを動かすまで

※Microsoft.CodeAnalysisのバージョンについて、Unity2022では 3.8、Unity6は4.3を指定している(公式ドキュメント)(2025/3/28現在)
※4.*の方がかなり機能が強化されているらしい

Unity公式
Roslyn アナライザーとソースジェネレーター – Unityマニュアル (Unity2022)
Unity Manual – Create and use a source generator

より実践的な開発手法(Incremental Source Generator)
参考
2022年(2024年)のC# Incremental Source Generator開発手法

機能が分かりやすくまとまっていて教科書にさせてもらった
【Unity用】Incremantal Source Generator プロジェクトの作り方

メモ
・IDEにはSourceGeneratorバランスモードというのが存在し、VisualStudioはデフォでバランスモードになっている。通常はコードを1文字書き換えるたびにSourceGeneratorが走るが、バランスモードだと保存時やビルド時にしか走らない。コード生成だけなら特に支障はないが、エラーや警告を出す処理をしている場合は注意。ビルド→SourceGeneratorが走る→コードの該当部位にエラーや警告の波線が出る→コードのどこか(関係ない箇所でも)を1文字でも書き換えると波線が消える→再度ビルドしないとエラー内容が見えない。みたいなことが起こる。回避策として、これらのコード分析処理は従来のAnalyzerに移す。SourceGeneratorバランスモードでもAnalyzerは1文字変更されるたびに走る。
・Analyzerのテストはとりあえずテストフレームワーク(xUnit,nUnit等)を入れ、「Microsoft.CodeAnalysis.Analyzers 3.3.3」「Microsoft.CodeAnalysis.CSharp 4.3.1」「Microsoft.CodeAnalysis.CSharp.Analyzer.Testing 1.1.2」「Microsoft.CodeAnalysis.CSharp.Workspaces 4.3.1」を入れ、以下のような感じでテストする。
テストをもっと書きやすくするライブラリが色々作られているみたいだが、そんなに頑張らなきゃいけないテストでもないし調査も大変なので、基本機能だけでテストした。

using Verify = Microsoft.CodeAnalysis.CSharp.Testing.CSharpAnalyzerVerifier<Kairou.SourceGenerator.CommandAnalyzer, Microsoft.CodeAnalysis.Testing.DefaultVerifier>;

    public class Tests
    {
        [Test]
        public async Task CommandMustBePartialClass()
        {
            var test = new CSharpAnalyzerTest<CommandAnalyzer, DefaultVerifier>()
            {
                TestState =
                {
                    Sources =
                    {"""
using Kairou;

public class TestCommand : Command
{
    [CommandExecute]
    void XXXX()
    {
        int x = 3;
    }
}
"""},
                    ExpectedDiagnostics =
                    {
                        Verify.Diagnostic(CommandAnalyzer.CommandMustBePartialClass)
                            .WithSpan(3, 14, 3, 25)
                            .WithArguments("TestCommand")
                    },
                }

            };
            test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(Config.DummyClassesDllPath));

            await test.RunAsync();
        }
    }

タイトルとURLをコピーしました