Share via


T4 テキスト テンプレートの記述に関するガイドライン

これらの一般的なガイドラインは、Visual Studio でプログラム コードやその他のアプリケーション リソースを生成する場合に役立ちます。 これらは固定規則ではありません。

デザイン時 T4 テキスト テンプレートのガイドライン

デザイン時 T4 テンプレートは、デザイン時に Visual Studio プロジェクト内のコードを生成するテンプレートです。 詳細については、「T4 テキスト テンプレートを使用したデザイン時コード生成」を参照してください。

アプリケーションの変数の側面を生成します。

コード生成は、プロジェクト中に変更される可能性がある、またはアプリケーションの異なるバージョン間で変更されるアプリケーションの側面に最も役立ちます。 これらの可変的な側面をより不変的な側面から分離して、生成する必要があるものをより簡単に決定できるようにします。 たとえば、アプリケーションが Web サイトを提供する場合は、標準のページ提供機能を、あるページから別のページへのナビゲーション パスを定義するロジックから分離します。

1 つ以上のソース モデルの可変的な側面をエンコードします。

モデルは、生成されるコードの可変部分の特定の値を取得するために各テンプレートが読み取るファイルまたはデータベースです。 モデルには、データベース、独自の設計の XML ファイル、図、またはドメイン固有の言語を使用できます。 通常は、1 つのモデルを使用して、Visual Studio プロジェクトで多数のファイルを生成します。 各ファイルは、個別のテンプレートから生成されます。

1 つのプロジェクトで複数のモデルを使用できます。 たとえば、Web ページ間のナビゲーション用のモデルと、ページのレイアウト用の別のモデルを定義できます。

実装ではなく、ユーザーのニーズとボキャブラリにモデルの焦点を当てます。

たとえば、Web サイト アプリケーションでは、モデルが Web ページとハイパーリンクを参照することが想定されます。

理想的には、モデルが表す情報の種類に適した表示形式を選択します。 たとえば、Web サイト内のナビゲーション パスのモデルは、ボックスと矢印の図です。

生成されたコードをテストします。

手動または自動テストを使用して、結果のコードがユーザーの要求どおりに機能することを確認します。 コードの生成元と同じモデルからテストを生成しないでください。

場合によっては、モデルに対して一般的なテストを直接実行できます。 たとえば、Web サイトのすべてのページに他のページからのナビゲーションでアクセスできることを確認するテストを作成できます。

カスタム コードを許可する: 部分クラスを生成します。

生成されたコードに加えて、手動でコードを記述できるようにします。 コード生成スキームで、発生する可能性のあるすべての可能なバリエーションを考慮することは通常ありません。 したがって、生成されたコードの一部を追加またはオーバーライドする必要があります。 生成された素材が C# や Visual Basic などの .NET 言語である場合、次の 2 つの戦略が特に役立ちます。

  • 生成されたクラスは、部分的なものである必要があります。 これにより、生成されたコードにコンテンツを追加できます。

  • クラスは、一方が他方を継承するペアで生成される必要があります。 基底クラスには生成されたすべてのメソッドとプロパティが含まれている必要があり、派生クラスにはコンストラクターのみが含まれている必要があります。 これにより、生成されたメソッドを手入力のコードでオーバーライドできます。

XML などの他の生成された言語では、<#@include#> ディレクティブを使用して、手入力のコンテンツと生成されたコンテンツを単純に組み合わせます。 より複雑なケースでは、生成されたファイルを手入力のファイルと組み合わせる後処理手順を記述しなければならない場合があります。

共通の素材をインクルード ファイルまたは実行時テンプレートに移動します。

複数のテンプレートで同様のテキストとコードのブロックを繰り返さないようにするには、<#@ include #> ディレクティブを使用します。 詳細については、「T4 インクルード ディレクティブ」を参照してください。

また、別のプロジェクトで実行時テキスト テンプレートを作成し、デザイン時テンプレートから呼び出すこともできます。 これを行うには、<#@ assembly #> ディレクティブを使用して別のプロジェクトにアクセスします。

大きなコード ブロックを別のアセンブリに移動することを検討してください。

大きなコード ブロックとクラス機能ブロックがある場合は、このコードの一部を別のプロジェクトでコンパイルするメソッドに移動すると便利な場合があります。 <#@ assembly #> ディレクティブを使用して、テンプレート内のコードにアクセスできます。 詳細については、「T4 アセンブリ ディレクティブ」を参照してください。

テンプレートが継承できる抽象クラスにメソッドを配置できます。 抽象クラスは、Microsoft.VisualStudio.TextTemplating.TextTransformation から継承する必要があります。 詳細については、T4 テンプレート ディレクティブに関するページを参照してください。

構成ファイルではなく、コードを生成します。

可変アプリケーションを記述する 1 つの方法は、構成ファイルを受け入れる汎用プログラム コードを記述することです。 この方法で記述されたアプリケーションは非常に柔軟であり、ビジネス要件が変更されたときにアプリケーションを再構築せずに再構成することができます。 ただし、このアプローチの欠点は、より具体的なアプリケーションよりもアプリケーションのパフォーマンスが低下することです。 また、そのプログラム コードは、ほとんどのジェネリック型を常に処理することになるため、読み取りと保守がより困難になります。

これに対して、コンパイル前に可変部分が生成されるアプリケーションは、厳密に型指定できます。 これにより、手入力のコードを記述し、ソフトウェアの生成された部分と統合することが、はるかに簡単で確実になります。

コード生成の利点を最大限に活用するには、構成ファイルではなくプログラム コードを生成してみてください。

Generated Code フォルダーを使用します。

テンプレートと生成されたファイルを "Generated Code" という名前のプロジェクト フォルダーに配置して、これらが直接編集する必要のあるファイルではないことを明確にします。 生成されたクラスをオーバーライドまたは追加するカスタム コードを作成する場合は、それらのクラスを "Custom Code" という名前のフォルダーに配置します。 一般的なプロジェクトの構造は次のようになります。

MyProject
   Custom Code
      Class1.cs
      Class2.cs
   Generated Code
      Class1.tt
          Class1.cs
      Class2.tt
          Class2.cs
   AnotherClass.cs

実行時 (前処理済み) T4 テンプレートに関するガイドライン

共通の素材を継承されたテンプレートに移動します。

継承を使用すると、T4 テキスト テンプレート間でメソッドとテキスト ブロックを共有することができます。 詳細については、T4 テンプレート ディレクティブに関するページを参照してください。

また、実行時テンプレートを含むインクルード ファイルを使用することもできます。

大規模なコード本体を部分クラスに移動します。

各実行時テンプレートでは、テンプレートと同じ名前を持つ部分クラス定義が生成されます。 同じクラスの別の部分定義が含まれているコード ファイルを作成できます。 この方法で、メソッド、フィールド、およびコンストラクターをクラスに追加できます。 これらのメンバーは、テンプレートのコード ブロックから呼び出すことができます。

これを行う利点は、IntelliSense を使用できるため、コードの記述が簡単になることです。 また、表示と基になるロジックをより適切に分離することもできます。

たとえば、MyReportText.tt の場合は、次のようになります。

The total is: <#= ComputeTotal() #>

MyReportText-Methods.cs の場合は、次のようになります。

private string ComputeTotal() { ... }

カスタム コードを許可する: 拡張ポイントを提供します。

<#+ class feature blocks #> で仮想メソッドを生成することを検討してください。 これにより、1 つのテンプレートを変更せずに多くのコンテキストで使用できます。 テンプレートを変更する代わりに、最小限の追加ロジックを提供する派生クラスを構築できます。 派生クラスは、通常のコードでも、実行時テンプレートでもかまいません。

たとえば、MyStandardRunTimeTemplate.tt の場合は、次のようになります。

This page is copyright <#= CompanyName() #>.
<#+ protected virtual string CompanyName() { return ""; } #>

アプリケーションのコードの場合は、次のようになります。

class FabrikamTemplate : MyStandardRunTimeTemplate
{
  protected override string CompanyName() { return "Fabrikam"; }
}
...
  string PageToDisplay = new FabrikamTemplate().TextTransform();

すべての T4 テンプレートのガイドライン

テキスト生成からデータ収集を分離します。

計算およびテキスト ブロックを混在させないようにしてください。 各テキスト テンプレートでは、最初の <# code block #> を使用して変数を設定し、複雑な計算を実行します。 最初のテキスト ブロックからテンプレートまたは最初の <#+ class feature block #> の最後まで、長い式を避け、テキスト ブロックが含まれていない限り、ループと条件を避けます。 これにより、テンプレートが読みやすくなり、保守も容易になります。

インクルード ファイルには .tt を使用しないでください。

インクルード ファイルには、.ttinclude などの別のファイル名拡張子を使用します。 .tt は、実行時またはデザイン時のテキスト テンプレートとして処理するファイルにのみ使用します。 場合によっては、Visual Studio で .tt ファイルが認識され、自動的にプロパティを処理するように設定されます。

各テンプレートを固定プロトタイプとして起動します。

生成するコードまたはテキストの例を記述し、それが正しいことを確認します。 その後、拡張子を .tt に変更し、モデルを読み取ってコンテンツを変更するコードを段階的に挿入します。

型指定されたモデルの使用を検討してください。

モデルの XML またはデータベース スキーマを作成することもできますが、ドメイン固有言語 (DSL) を作成すると便利な場合があります。 DSL には、スキーマ内の各ノードを表すクラスと、属性を表すプロパティが生成されるという利点があります。 これは、ビジネス モデルの観点からプログラミングできることを意味します。 次に例を示します。

Team Members:
<# foreach (Person p in team.Members)
 { #>
    <#= p.Name #>
<# } #>

モデルに図を使用することを検討してください。

多くのモデルは、特に非常に大きい場合に、テキスト テーブルとして最も効果的に表示および管理されます。

ただし、ビジネス要件によっては、複雑な一連の関係とワークフローを明確にすることが重要であり、図は最適な媒体です。 図の利点は、ユーザーや他の利害関係者と議論しやすいことです。 ビジネス要件のレベルでモデルからコードを生成することで、要件が変更されたときにコードの柔軟性を高めることができます。

また、独自の種類の図をドメイン固有言語 (DSL) として設計することもできます。 コードは、UML と DSL の両方から生成できます。 詳細については、「アーキテクチャを分析およびモデリングする」を参照してください。