かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Viausl Studio 2010で自作コードジェネレータ

コードの自動生成は、色々なところでされていると思います。Excelのマクロで作ったり、自分でせっせとコードを書いたり、LLな言語を使ってさくっと作ったり、OSSのテンプレートエンジンで作ったり etc...


そんな中で、1つコードジェネレータを作るときの選択肢として追加しても良さそうな機能がVisual Studio 2010にあります。その名も「前処理されたテキストテンプレート」です。正直、この名前から何をするものかってさっぱりわかりませんが、コードジェネレータとかを作るときにもってこいの、デキル奴だったりします。


とりあえず、Hello worldから始めてみましょう。HelloCodeGeneratorという名前でコンソールアプリケーションを作成します。そこに「HelloPreTextTemplate.tt」という名前で「前処理されたテキストテンプレート」を作成します。

HelloPreTextTemplate.ttのファイルの中身を以下のようにします。

<#@ template language="C#" #>
Hello world

そして、Mainメソッドに以下のようなコードを書きます。

namespace HelloCodeGenerator
{
    using System;

    class Program
    {
        static void Main(string[] args)
        {
            var template = new HelloPreTextTemplate();
            Console.WriteLine(template.TransformText());
        }
    }
}


これで、Hello worldというテキストを生成するジェネレータが出来ました。さっそく実行してみると、以下のような結果が得られると思います。

Hello world


といった感じで.ttファイルで書いたテンプレートに従ったテキストを生成してくれるクラスが勝手に出来上がるという素敵なものです。
といっても、この例じゃ有難味が分かりにくいので、もうちょっとだけ実用的な感じにしてみようと思います。

HelloPreTextTemplate.custom.csという名前でクラスを作成して、以下のようなプロパティを追加します。

namespace HelloCodeGenerator
{
    public partial class HelloPreTextTemplate
    {
        public string ClassName { get; set; }

        public string[] PropertyNames { get; set; }
    }
}

そして、HelloPreTextTemplate.ttの中身を以下のように書き換えます。

<#@ template language="C#" #>
class <#= ClassName #>
{
<# 
foreach (var name in PropertyNames)
{
#>
	public string <#= name #> { get; set; }
<#
}
#>
}

ここで注目なのは、T4 Templateの中でClassNameやPropertyNamesといった先ほどHelloPreTextTemplateクラスに追加したプロパティが使えることです。Mainメソッドを以下のように変更してClassNameやPropertyNamesを設定してやるようにします。

namespace HelloCodeGenerator
{
    using System;

    class Program
    {
        static void Main(string[] args)
        {
            var template = new HelloPreTextTemplate
            {
                ClassName = "Person",
                PropertyNames = new[] { "Name", "Profile" }
            };

            Console.WriteLine(template.TransformText());
        }
    }
}

これを実行すると、以下のような結果が得られます。

class Person
{
        public string Name { get; set; }
        public string Profile { get; set; }
}

非常にお手軽にクラスのコードを生成するジェネレータが出来ました。こいつはいいかも。