T4 テキスト テンプレートを使用したデザイン時コード生成
デザイン時 T4 テキスト テンプレートを使用して、Visual Studio プロジェクトのプログラム コードや他のファイルを生成できます。テンプレートを作成するときは、モデルのデータに応じて生成されるコードが変わるようにするのが一般的です。モデルとは、アプリケーションの要件に関する重要な情報が含まれたファイルまたはデータベースのことです。
たとえば、ワークフローをテーブルまたは図として定義したモデルがあるとします。このモデルから、ワークフローを実行するソフトウェアを生成できます。ユーザーの要件が変わったときに、新しいワークフローについてユーザーと共に検討しやすくなります。ワークフローからコードを再生成すると、コードを手動で更新するよりも信頼性が高まります。
[!メモ]
モデルは、アプリケーションの特定の側面を記述したデータ ソースです。モデルはどのような形式でもかまいません。あらゆる種類のファイルまたはデータベースを使用できます。UML モデルやドメイン固有言語モデルなどの特定の形式である必要はありません。標準的なモデルの形式は、テーブルまたは XML ファイルです。
コード生成は決して新しい概念ではありません。Visual Studio ソリューションにある .resx ファイルでリソースを定義すると、一連のクラスおよびメソッドが自動的に生成されます。リソースの編集は、クラスやメソッドを直接編集するよりも、リソース ファイルで行った方がはるかに簡単で確実です。同様に、テキスト テンプレートを使用すると、独自に設計したソースからコードを生成することができます。
テキスト テンプレートには、生成するテキストと、テキストの可変部分を生成するプログラム コードの組み合わせが含まれます。プログラム コードにより、生成されるテキストの一部を繰り返したり、条件に従って省略したりできるようになります。生成されるテキスト自体を、アプリケーションの一部となるプログラム コードにすることもできます。
デザイン時 T4 テキスト テンプレートを作成する
Visual Studio でデザイン時 T4 テンプレートを作成するには
Visual Studio プロジェクトを作成するか、既存のプロジェクトを開きます。
たとえば、[ファイル] で、メニューの [新規作成]、**[プロジェクト]**を選択します。
テキスト テンプレート ファイルをプロジェクトに追加し、拡張機能の.ttを持つ名前を付けます。
これを、プロジェクトのショートカット メニューので、[ソリューション エクスプローラー]するには、[追加]、**[新しい項目]**を選択します。中央のペインから [新しい項目の追加] のダイアログ ボックスを [テキスト テンプレート]。
ファイルの [カスタム ツール] プロパティが TextTemplatingFileGenerator となっていることに注目してください。
ファイルを開きます。既に次のディレクティブが指定されています。
<#@ template hostspecific="false" language="C#" #> <#@ output extension=".txt" #>
Visual Basic プロジェクトにテンプレートを追加した場合、言語属性は "VB" になります。
ファイルの最後にテキストを追加します。次に例を示します。
Hello, world!
ファイルを保存します。
テンプレートを実行してよいか確認する [セキュリティ警告] メッセージ ボックスが表示されます。[OK] をクリックします。
**[ソリューション エクスプローラー]**で、テンプレート ファイル ノードを展開すると、拡張子が.txtのファイルを検索します。ファイルは、テンプレートから生成されるテキストが含まれます。
[!メモ]
プロジェクトがVisual Basicプロジェクトの場合、出力ファイルを確認するに [すべてのファイルを表示] をクリックする必要があります。
コードの再生成
次のいずれかの場合に、テンプレートが実行され、従属ファイルが生成されます。
テンプレートを編集し、Visual Studio の別のウィンドウにフォーカスを変更します。
テンプレートを保存したとき。
[ビルド] のメニューのをクリック [すべてのテンプレートの変換]。この場合、Visual Studio ソリューション内のすべてのテンプレートが変換されます。
各ファイルのショートカット メニューの **[ソリューション エクスプローラー]では、[カスタム ツールの実行]**を選択します。テンプレートの選択したサブセットを変換するには、このメソッドを使用します。
読み取り先のデータ ファイルが変更されたときにテンプレートが実行されるよう、Visual Studio プロジェクトを設定することもできます。詳細については、「コードを自動的に再生成する」を参照してください。
可変テキストを生成する
テキスト テンプレートから生成されるファイルのコンテンツは、プログラム コードを使用して変化させることができます。
プログラム コードを使用してテキストを生成するには
.tt ファイルの内容を次のように変更します。
<#@ template hostspecific="false" language="C#" #> <#@ output extension=".txt" #> <#int top = 10; for (int i = 0; i<=top; i++) { #> The square of <#= i #> is <#= i*i #> <# } #>
<#@ template hostspecific="false" language="VB" #> <#@ output extension=".txt" #> <#Dim top As Integer = 10 For i As Integer = 0 To top #> The square of <#= i #> is <#= i*i #> <# Next #>
.tt ファイルを保存し、生成された .txt ファイルを再度確認します。0 から 9 の数値を 2 乗した値が一覧表示されます。
複数のステートメントは <#...#> で囲まれており、単一の式は <#=...#> で囲まれていることに注意してください。詳細については、「T4 テキスト テンプレートの作成」を参照してください。
Visual Basic で生成コードを記述する場合は、template ディレクティブに language="VB" を含める必要があります。"C#" が既定値です。
デザイン時T4テキスト テンプレートをデバッグ
テキスト テンプレートをデバッグするには:
template ディレクティブに debug="true" を挿入します。次に例を示します。
<#@ template debug="true" hostspecific="false" language="C#" #>
テンプレート、同じように、通常のコードについて、そのブレークポイントを設定します。
ソリューション エクスプローラーのテキスト テンプレート ファイルのショートカット メニューから [T4 テンプレートのデバッグ] を選択します。
テンプレートは、ブレークポイントで実行が停止します。通常の方法でコードによって変数とステップを確認できます。
ヒント |
---|
debug="true" は、テキスト テンプレートに生成されたコードに行番号のディレクティブを挿入して、生成されたコード マップを、より正確になります。これを省けば、ブレークポイントは不適切な状態の実行を停止する可能性があります。 ただし、デバッグ場合でも、テンプレート ディレクティブに句を保持できます。これにより、パフォーマンスの非常に小さなドロップのみ発生します。 |
ソリューションのコードまたはリソースを生成する
生成するプログラム ファイルは、モデルに応じて変化させることができます。モデルは入力です。たとえば、データベース、構成ファイル、UML モデル、DSL モデルなど、各種のソースがそれに該当します。プログラム ファイルは、同じモデルから複数生成するのが一般的です。そのためには、生成するプログラム ファイルごとにテンプレート ファイルを作成し、すべてのテンプレートで同じモデルを読み取るようにします。
プログラム コードまたはリソースを生成するには
適切な種類のファイル (.cs、.vb、.resx、.xml など) を生成するように output ディレクティブを変更します。
必要なソリューション コードを生成するためのコードを挿入します。たとえば、クラス内に整数型のフィールド宣言を 3 つ生成するには、次のようにします。
<#@ template debug="false" hostspecific="false" language="C#" #> <#@ output extension=".cs" #> <# var properties = new string [] {"P1", "P2", "P3"}; #> class MyGeneratedClass { <# foreach (string propertyName in properties) { #> private int <#= propertyName #> = 0; <# } #> }
<#@ template debug="false" hostspecific="false" language="VB" #> <#@ output extension=".cs" #> <# Dim properties = {"P1", "P2", "P3"} #> class MyGeneratedClass { <# For Each propertyName As String In properties #> private int <#= propertyName #> = 0; <# Next #> }
ファイルを保存し、生成されたファイルを調べると、次のコードが含まれていることがわかります。
class MyGeneratedClass { private int P1 = 0; private int P2 = 0; private int P3 = 0; }
生成コードと生成されたテキスト
プログラム コードを生成する際に最も重要なことは、テンプレート内で実行されるコード生成機構 (コードを生成するためのコード) と、結果として生成されるコード (ソリューションの一部になるコード) とを混同しないことです。2 つの言語が必ずしも一致している必要はありません。
前の例は、2 つのバージョンで構成されています。1 つ目のバージョンは C# のコードで生成されます。2 つ目のバージョンは、Visual Basic のコードで生成されます。ただし、両方のコードで生成されるテキストは同じであり、C# クラスです。
同様に、Visual C# テンプレートは、どのような言語のコードでも生成できます。生成されるテキストは、プログラム コードが含まれる固有の言語である必要はありません。
テキスト テンプレートの構成
ここでは、テンプレート コードを次の 2 つの部分に分けています。
構成またはデータ収集の部分。この部分では変数に値を設定しますが、テキスト ブロックは含まれません。前の例では、properties の初期化の部分が該当します。
この部分はインストア モデルを構築し、通常はモデル ファイルを読み取るため、"モデル" セクションとも呼ばれます。
テキスト生成部分 (この例では、foreach(...){...})。この部分では変数の値を使用します。
必ずしもこのように分ける必要はありませんが、このように記述すると、テキストを含む部分の複雑さが軽減され、テンプレートが読みやすくなります。
ファイルなど各種ソースを読み取る
モデル ファイルまたはモデル データベースにアクセスするために、テンプレート コードで System.XML などのアセンブリを使用できます。これらのアセンブリにアクセスするためには、次のようなディレクティブを挿入する必要があります。
<#@ assembly name="System.Xml.dll" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.IO" #>
assembly ディレクティブでアセンブリを指定することによって、Visual Studio プロジェクトの [参照設定] セクションに表示されるアセンブリと同じように、指定されたアセンブリにテンプレート コードからアクセスすることができます。System.dll への参照を含める必要はありません。System.dll は自動的に参照されます。import ディレクティブの効果は、完全修飾名を使用せずに型を指定できるようになることです。通常のプログラム ファイルで using ディレクティブを使用した場合と同様です。
たとえば、System.IO のインポート後に、次のようなコードを記述できます。
<# var properties = File.ReadLines("C:\\propertyList.txt");#>
...
<# foreach (string propertyName in properties) { #>
...
<# For Each propertyName As String In
File.ReadLines("C:\\propertyList.txt")
#>
相対パス名を指定してファイルを開く
テキスト テンプレートを基準とする場所からファイルを読み込むには、this.Host.ResolvePath() を使用します。this.Host を使用するには、次のように template で hostspecific="true" を設定する必要があります。
<#@ template debug="false" hostspecific="true" language="C#" #>
これで、次のようなコードを記述できるようになります。
<# string fileName = this.Host.ResolvePath("filename.txt");
string [] properties = File.ReadLines(filename);
#>
...
<# foreach (string propertyName in properties { #>
...
<# Dim fileName = Me.Host.ResolvePath("propertyList.txt")
Dim properties = File.ReadLines(filename)
#>
...
<# For Each propertyName As String In properties
...
#>
this.Host.TemplateFile を使用して、現在のテンプレート ファイルの名前を示すこともできます。
this.Host (VB の場合は Me.Host) の型は、Microsoft.VisualStudio.TextTemplating.ITextTemplatingEngineHost です。
Visual Studio からデータを取得する
Visual Studioで提供されるサービスを使用するには、hostSpecific の属性を設定し、EnvDTE のアセンブリを読み込みます。その後、DTEおよびそのほかのサービスへのアクセスに IServiceProvider.GetCOMService() を使用できます。次に例を示します。
<#@ template hostspecific="true" language="C#" #>
<#@ output extension=".txt" #>
<#@ assembly name="EnvDTE" #>
<#
IServiceProvider serviceProvider = (IServiceProvider)this.Host;
EnvDTE.DTE dte = (EnvDTE.DTE) serviceProvider.GetCOMService(typeof(EnvDTE.DTE));
#>
Number of projects in this VS solution: <#= dte.Solution.Projects.Count #>
ヒント |
---|
テキスト テンプレートは独自のアプリケーション ドメインで実行されるサービスは、マーシャリングによってアクセスします。この状況では、GetCOMService() は GetService()信頼性も高まります。 |
コードを自動的に再生成する
Visual Studio ソリューションには、1 つの入力モデルを使用して複数のファイルを生成するのが一般的です。各ファイルはそれぞれ対応するテンプレートから生成されますが、すべてのテンプレートは同じモデルを参照します。
ソース モデルが変更された場合は、ソリューションのすべてのテンプレートを再度実行する必要があります。これは手動で行うには、[ビルド] のメニューの [すべてのテンプレートの変換] を選択します。
Visual Studio Visualization and Modeling SDK がインストールされている場合は、ビルドを実行するたびにすべてのテンプレートが自動的に変換されるように設定できます。そのためには、プロジェクト ファイル (.csproj または .vbproj) をテキスト エディターで編集し、ファイルの末尾付近の、他の <import> ステートメントよりも後に次のコード行を追加します。
<Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v11.0\TextTemplating\Microsoft.TextTemplating.targets" />
<PropertyGroup>
<TransformOnBuild>true</TransformOnBuild>
<!-- Other properties can be inserted here -->
</PropertyGroup>
詳細については、「ビルド処理でのコード生成」を参照してください。
エラー レポート
エラー メッセージおよび警告メッセージを Visual Studio のエラー ウィンドウに表示するには、次のメソッドを使用します。
Error("An error message");
Warning("A warning message");
既存のファイルをテンプレートに変換する
テンプレートには、見た目は生成されるファイルとよく似ていて、そこに、プログラム コードが挿入されているという特徴があります。このことを利用すると、テンプレートを効率的に作成することができます。最初に通常のファイル (Visual C# ファイルなど) をプロトタイプとして作成し、その後、結果のファイルにバリエーションを持たせるための生成コードを徐々に適用していく方法です。
既存のファイルをデザイン時テンプレートに変換するには
.cs、.vb、.resx など、生成する種類のファイルを Visual Studio プロジェクトに追加します。
この新しいファイルをテストして、ファイルが機能することを確認します。
ソリューション エクスプローラーで、ファイル名拡張子を .tt に変更します。
.tt ファイルの次のプロパティを確認します。
カスタム ツール =
TextTemplatingFileGenerator
ビルド アクション =
なし
ファイルの先頭に次の行を挿入します。
<#@ template debug="false" hostspecific="false" language="C#" #> <#@ output extension=".cs" #>
テンプレートのコード生成機構を Visual Basic で記述する場合は、language 属性を "C#" ではなく、"VB" に設定してください。
extension 属性を、生成するファイルの種類のファイル名拡張子 (.cs、.resx、.xml など) に設定します。
ファイルを保存します。
指定された拡張子の従属ファイルが作成されます。そのプロパティは、ファイルの種類に対応します。たとえば、.cs ファイルの [ビルド アクション] プロパティは [コンパイル] になります。
生成されたファイルのコンテンツが、元のファイルと同じであることを確認します。
ファイルの可変部分を見極めます。たとえば、特定の条件を満たした場合にのみ出力する部分や、繰り返し出力する部分、特定の値をどこで変化させるかなどを決めます。コードを生成するためのコードを挿入します。ファイルを保存し、従属ファイルが正しく生成されたことを確認します。この手順を繰り返します。
コード生成のガイドライン
「T4 テキスト テンプレートの記述に関するガイドライン」を参照してください。
次の手順
次の手順 |
トピック |
---|---|
補助的な関数、インクルード ファイル、永続データなどを使用したコードを組み合わせて、より高度なテキスト テンプレートを作成し、デバッグする。 |
|
実行時にテンプレートからドキュメントを生成する。 |
|
Visual Studio の外部でテキストの生成を行う。 |
|
ドメイン固有言語の形式でデータを変換する。 |
|
独自のデータ ソースを変換するためのディレクティブ プロセッサを作成する。 |