T4 Templateを使ってみよう!

このページの記載事項を試すには、Visual Studio 2005 Professional以上が必要です。また、Visual Studio 2005 SDKのインストールもお願いします。Visal Studio 2008でも使用可能です。

先ずは、Visual Studioで新しいプロジェクトを作成しましょう。そして作成したプロジェクトに、拡張子を"tt"として、テキストファイルを新規に追加します。ファイルの名前は、"sample.tt"として話を進めます。
ソリューションエクスプローラーでsample.ttを選択し、プロパティを表示してみてください。カスタムツールの項目の値が、"TextTemplatingFileGenerator”に自動的に設定されているのがわかるでしょう。この設定により、sample.ttファイルを変更し保存するたびに、TextTemplatingFileGeneratorによって解釈され、sample.ttの内容に従ったテキストファイルが生成されます。

sample.ttの内容は、T4 Templateで決められた文法に従って記述します。T4 Templateでの記述内容は大きく5種類に分類できます。3種類とは

  1. テンプレートに関するDirective宣言
  2. テキスト部分
  3. 変数のテキストへの変換 
  4. テキストへの変換に必要なロジック
  5. メソッドの定義

以下に順番に説明していきましょう。

先ず1番目の「テンプレートに関するDirective宣言」です。テンプレート内で、<#@ directive variable="value" ・・・#>の形式で書かれた部分がDirective宣言です。Directive宣言は、テンプレートの先頭に位置します(テキスト部分は先に定義されていても良いようです)。Directive宣言は、テンプレートをコントロールする様々な宣言です。
例として、DSL Designerで作成したDSL Modelに対するテンプレートの場合は、

<#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation" debug="true"#>
<#@ output extension=".txt" #>
<#@ DSLName processor="DSLNameDirectiveProcessor" requires="fileName=DSLModel.sdfd'" #>

の様な記述になります。最初のtemplateは、テンプレートがModelingTextTransformationクラスを継承して定義すること、デバッグモードで実行することを指定しています。二番目のoutputは、このテンプレートを実行したときに生成されるファイルの拡張子を指定しています。3行目の宣言と合わせ、このテンプレートはDSLModel.txtという名前のファイルを生成します。
3行目は、このテンプレートにデータを供給するプロセッサーを指定します。DSLNameDSLNameDirectiveProcessorは、DSLNameの部分がそれぞれのDSLの名前を指定します。
DSLNameDirectiveProcessorは、DSLを定義した時に自動的に生成されるクラスです。この3行でfileNameとしてDSLModel.sdfdを指定していますが、これは、このファイルが変更される度に、子の変換テンプレートが実行されることを意味します。
他に、使用できるDirectiveには、ImportやIncludeなど多数あります。詳しくは、

MSDN→MSDN Library→Development Tools and Languages→Visual Studio 2005→Visual Studio→Visual Studio SDK→Domain-Specific Language Tools → Creating Domain-Specific Languages →Generating Artifacts Using TextTemplate → Using Built-in Directives In Text Template

を参照してください。

次に、2番目の「テキスト部分」です。テンプレート内で、<# #>で囲まれていない、平文は、そのままテキストとして生成されます。固定的にテキストを生成したい場合に用います。

次に、3番目の「変数のテキストへの変換」です。形式は<#= 変数名 #>です。この変数名の部分が、その変数の値に置き換わります。例えば、nameという変数があり、その値がTemplateの場合、テンプレートの記述は

<#= name #>

となり、変換後は、

Template

になります。変数名の部分は、変数.プロパティの形式でも構いません。次に説明するロジックと組み合わせることにより望みの変換ルールを書くことができます。

次に、4番目の「テキストへの変換に必要なロジック」です。
テキストテンプレートの中で<# #>で囲まれた部分がロジックを記述する部分として解釈されます。この部分では、Directive宣言で指定されたプログラミング言語によって必要な処理を記述します。この部分で記述できるのは、通常のメソッドの処理で記述できる文法的、意味的に正しいすべてのプログラム文です。以下、すべてC#を使うものとして説明します。たとえば、型List<String>の変数listに格納された文字列を戦闘のみ大文字に変換して順番にテキスト化したい場合

<#
    foreach (String item in list)
    {
        String text = item.Substring(0,1).ToUpper() + item.Substring(1,item.Length-1).ToLower();
#>
    - <#= text #>
<#
    }
#>

こんな感じです。listの中に、"apple","orange","PEACH"が格納されている場合は、

    - Apple
    - Orange
    - Peach

に変換されます。ちなみに、DSL Model用のDirectiveProcessorをDirective宣言している場合は、DSL Modelのルートクラスを

this.RootClass

で参照可能です。

最後に、5番目の「メソッドの定義」です。テンプレートに変換ルールを記述しているとき、変換ルールの規模が大きくなると、一纏りの処理が何十行にも渡ったり、同じ処理が繰り返し現れたり、再帰的なコードが必要な場合が必ず発生します。こんな時には、通常のオブジェクト指向と同様、メソッドとして別の場所で定義しておき、メソッドコールを利用すると変換ルールが分かりやすく、メンテナンスしやすくなります。こんな場合にメソッドの定義を使います。メソッドの定義は、<#+ #>で囲み、その中で、通常のクラスのメソッドを定義するのと同様な記述を行います。

<#+
private Type foo(arguments...)
{
    ・・・・
}
#>

メソッド定義は、テンプレートの最後の方にまとめて定義しておきます。なぜこの記述が機能するかというと、テンプレートファイルは、変換の実行に先立って、クラスに一旦変換され、そのクラスを実行することによって実際の変換が実行されているからです。

DSL Designerのプロジェクトテンプレートとしてあらかじめ用意されているMinumam Languageを使ってプロジェクトを生成し、そのままデバッグを起動してみてください。立ち上がった新しいVisual StudioにはDebugという名前のプロジェクトが用意されているはずです。その中に、T4 Templateが2つ用意されています。その記述内容をいろいろと変更し、変換を試してみてください。

T4 Templateを使ってT4 Templateを生成することもできます。既存のコードのテンプレート化やテンプレートそのものの自動生成、Wizardとの組み合わせなどにより、様々な応用が考えられ、それらを活用することにより、コーディングのかなりの部分を自動化することが可能になります。

・・・と、これまで説明すると、DSL抜きでもT4 Templateを使ってみたい、プログラムの中からT4 Templateの変換を実行したいと思われた方、そのやりかたは、また別のページで紹介します。