コントロール ブロックを使用すると、出力を変更するためにテキスト テンプレートにコードを記述できます。 コントロール ブロックは 3 種類あり、左山かっこで区別されます。
<# Standard control blocks #>
には、ステートメントを含めることができます。<#= Expression control blocks #>
には、式を含めることができます。<#+ Class feature control blocks #>
には、メソッド、フィールドおよびプロパティを含めることができます。
標準コントロール ブロック
標準コントロール ブロックには、ステートメントを含めることができます。 たとえば、次の標準ブロックは、XML ドキュメント内のすべての属性の名前を取得します。
<#@ assembly name="System.Xml.dll" #>
<#@ import namespace="System.Xml" #>
<#
List<string> allAttributes = new List<string>();
XmlDocument xDoc = new XmlDocument();
xDoc.Load(@"E:\CSharp\Overview.xml");
XmlAttributeCollection attributes = xDoc.Attributes;
if (attributes.Count > 0)
{
foreach (XmlAttribute attr in attributes)
{
allAtributes.Add(attr.Name);
}
}
#>
if
や for
などの複合ステートメント内に、プレーンテキストを埋め込むことができます。 たとえば、次のフラグメントでは、各ループの反復処理で出力行が生成されます。
<#
foreach (XmlAttribute attr in attributes)
{
#>
Found another one!
<#
allAtributes.Add(attr.Name);
}
#>
警告
埋め込みプレーン テキストを含む入れ子になったステートメントを区切る場合は、常に {...} を使用します。 次の例は正しく動作しません。
<# if (ShouldPrint) #> Some text. -- WRONG
次のように、中かっこ ({ }) を含める必要があります。
<#
if (ShouldPrint)
{ // "{" REQUIRED
#>
Some text.
<#
}
#>
式コントロール ブロック
式コントロール ブロックは、出力ファイルに書き込まれる文字列を提供するコードで使用します。 たとえば、前の例のコード ブロックを次のように変更すると、属性の名前を出力ファイルに出力できます。
<#
XmlDocument xDoc = new XmlDocument();
xDoc.Load(@"E:\CSharp\Overview.xml");
XmlAttributeCollection attributes = xDoc.Attributes;
if (attributes != null)
{
foreach (XmlAttribute attr in attributes)
{
#><#= attr.Name #><#
}
}
#>
クラス機能コントロール ブロック
クラス機能コントロール ブロックを使用すると、メソッド、プロパティ、フィールド、または入れ子になったクラスをテキスト テンプレートに追加できます。 クラス機能ブロックの最も一般的な用途は、テキスト テンプレートの他の部分のコードにヘルパー関数を提供することです。 たとえば、次のクラス機能ブロックは、属性名の最初の文字を大文字にします (名前に空白文字が含まれている場合は、各単語の最初の文字を大文字にします)。
<#@ import namespace="System.Globalization" #>
<#+
private string FixAttributeName(string name)
{
return CultureInfo.CurrentCulture.TextInfo.ToTitleCase(name);
}
#>
Note
同じテンプレート ファイル内で、クラス機能コントロール ブロックの後に標準コントロール ブロックを配置することはできません。 ただし、この制限は、<#@include#>
ディレクティブを使用した結果には適用されません。 各インクルード ファイルでは、標準ブロックの後にクラス機能ブロックを配置できます。
クラス機能コントロール ブロック内にテキスト ブロックと式ブロックを埋め込むことによって、出力を生成する関数を作成できます。 たとえば次のような点です。
<#+
private void OutputFixedAttributeName(string name)
{
#>
Attribute: <#= CultureInfo.CurrentCulture.TextInfo.ToTitleCase(name) #>
<#+ // <<< Notice that this is also a class feature block.
}
#>
標準ブロックまたは別のクラス機能ブロックから、この関数を呼び出すことができます。
<# foreach (Attribute attribute in item.Attributes)
{
OutputFixedAttributeName(attribute.Name);
}
#>
コントロール ブロックの使用方法
1 つのテンプレート内の標準コントロール ブロックと式コントロール ブロックのコード (インクルードされたテンプレート内のコードも含む) はすべて結合され、生成されるコードの TransformText()
メソッドを形成します (include
ディレクティブを使用して他のテキスト テンプレートをインクルードする方法の詳細については、「T4 テキスト テンプレートのディレクティブ」を参照してください)。
コントロール ブロックの使用時には、次の考慮事項に留意してください。
言語。 テキスト テンプレートでは、C# または Visual Basic のコードを使用できます。 既定の言語は C# ですが、
template
ディレクティブのlanguage
パラメーターで Visual Basic を指定できます。 (template
ディレクティブの詳細については、「T4 テキスト テンプレートのディレクティブ」を参照してください)。コントロール ブロックで使用する言語は、テキスト テンプレートで生成するテキストの言語または書式とは無関係です。 Visual Basic コードを使用して C# を生成することも、C# コードを使用して Visual Basic を生成することもできます。
include
ディレクティブでインクルードするすべてのテキスト テンプレートを含め、特定のテキスト テンプレートで使用できる言語は 1 つだけです。ローカル変数。 テキスト テンプレート内の標準コントロール ブロックと式コントロール ブロックのコードはすべて結合され、単一のメソッドとして生成されるため、各ローカル変数の名前が競合しないように注意してください。 他のテキスト テンプレートをインクルードする場合は、インクルードされるすべてのテンプレート間で変数名を一意にする必要があります。 これを実現する 1 つの方法は、各ローカル変数名に、その変数が宣言されたテキスト テンプレートを識別する文字列を追加することです。
特に複数のテキスト テンプレートをインクルードする場合は、ローカル変数を宣言するときに、そのローカル変数を妥当な値に初期化するのも良い方法です。
コントロール ブロックの入れ子。 コントロール ブロックどうしを入れ子にすることはできません。 次のコントロール ブロックを開始する前に、前のコントロール ブロックを必ず終了する必要があります。 たとえば、式ブロック内のテキストを標準コントロール ブロックの一部として出力する方法を次に示します。
<# int x = 10; while (x-- > 0) { #> <#= x #> <# } #>
リファクタリング。 テキスト テンプレートを簡潔で理解しやすい状態に保つために、コードの繰り返しを避けることを強くお勧めします。そのためには、再利用できるコードをクラス機能ブロックのヘルパー関数にファクタリングするか、Microsoft.VisualStudio.TextTemplating.TextTransformation クラスを継承する独自のテキスト テンプレート クラスを作成します。