C#のテキストテンプレートを使ってみた(1)
ランタイムテキストテンプレートの場合

どもです。

今回は、C#の「テキストテンプレート」を使ってみたので、その内容について書きます。

1.「テキストテンプレート」とは

「テキストテンプレート」とは、C#で使用可能な、テンプレートからファイルやコードを生成する機能です。
このテンプレートでは、C#の構文が使用可能であるため、より柔軟なテンプレートの生成が可能です。

2.テンプレートの種類

C#で使用可能なテンプレートは、「テキストテンプレート」と「ランタイムテキストテンプレート」の2種類があります。

2.1.「テキストテンプレート」

「テキストテンプレート」は、「デザイン時コード生成」とも言われます。
その名の通り、「アプリケーションの実行時」ではなく、「アプリケーションの設計(実装)時」に、テンプレートからテキストを生成します。
このテンプレートから生成されたコードは、そのままビルド対象にすることができます。
そのため、同じようなコードを繰り返し実装したりする場合には、この方法がとても便利(な様子)です。

2.2.「ランタイムテキストテンプレート」

「ランタイムテキストテンプレート」は、「プログラムの実行時にテンプレートからコードを生成する」ためのテンプレートです。
いわゆる「フツーのテンプレート」の使い方になります。
今回のエントリでは、コチラのテンプレートについて書きます。

3.ランタイムテキストテンプレートを使ってみる

実際にランタイムテキストテンプレートを使ってみます。
なお、開発環境は以下の通りです。

OS Windows10 Pro
ver.1903
CPU i7-8700
IDE VisualStudioCommunity2019
ver.16.5.1
.Net Framework 4.7
アプリケーションの種類 コンソールアプリケーション

3.1.プロジェクトへの追加

今回は、コンソールアプリケーションでランタイムテキストテンプレートを使用します。
まず、テキトーなソリューション/プロジェクトを作成します。
作成したら、次はプロジェクトで[右クリック]→[追加]→[新しい項目]を選択します。
「新しい項目の追加」ダイアログが表示されますので、左側の「全般」を選択し、真ん中の一覧から「ランタイムテキストテンプレート」を選択します。
「名前」は、任意の名前を設定してください。
今回は、デフォルトの値(RunTimetextTemplate1.tt)としています。
以上で、ランタイムテキストテンプレートのプロジェクトへの追加は完了です。

3.2.使ってみる

追加したテンプレートの中身を確認してみます。
デフォルトでは、以下のようになっています。

<#@ template language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>

また、ソリューションエクスプローラでは、「RunTimetextTemplate1.tt」の子ノードとして、「RuntimeTextTemplate1.cs」が生成されます。
このファイルが、テンプレートの内容を出力する処理を実装するクラスになります。

これで、ランタイムテキストテンプレートを使用する準備が整いました。
今回はこのテンプレートを使用して、先述の開発環境のHTML形式のテーブル(tableタグ)を生成してみます。

3.2.1.ゴールの確認!

ゴール地点は、以下のようなテキストがテンプレートから生成されることとします。

<table>
<tbody>
	<tr>
		<th>OS</th>
		<td>Windows10 Pro<br>ver.1903</td>
	</tr>
	<tr>
		<th>CPU</th>
		<td>i7-8700</td>
	</tr>
	<tr>
		<th>IDE</th>
		<td>VisualStudioCommunity2019<br>ver.16.5.1</td>
	</tr>
	<tr>
		<th>.Net Framework</th>
		<td>4.7</td>
	</tr>
	<tr>
		<th>アプリケーションの種類</th>
		<td>コンソールアプリケーション</td>
	</tr>
</tbody>
</table>

3.2.2.テンプレートの実装

ゴールの内容を確認すると、trタグの繰り返しがあることが分かります。
そこで、trタグに対応するリストの内容を繰り返し文で出力すテンプレートを作成します。
実装は以下!

<table>
	<tbody>
<# foreach (var item in TableItems) { #>
		<tr>
			<th><#= item.Header #></th>
			<tr><#= item.Data #></th>
		</tr>
<# } #>
	</tbody>
</table>

先述の通り、C#のテキストテンプレートでは、C#の構文が使用可能です。
C#のテキストテンプレートでは、「<# #>」で囲んだ範囲はC#の構文となります。
上述のコードでは、foreach文の開始と終了で使用しています。
また、変数の値を出力する場合には、「<#= #>」で変数を囲みます。
これは、テキストテンプレートの「コントロールブロック」と呼びます。
他にも色々なモノがあるようです。
それらについては、Microsoftのサイトを参照して下さい。

3.2.3.モデルの実装

次に、テキストテンプレートで使用するモデルです。
上述のテキストテンプレートから、「Header」と「Data」というプロパティを持つモデルを定義すればよいことが分かります。
そこで、以下のクラスをモデルクラスとして実装します。

public class DevEnv
{
	public string Header { get; set; }
	public string Data { get; set; }

	public DevEnv(string header, string data)
	{
		this.Header = header;
		this.Data = data;
	}
}

3.2.4.テンプレートの実装(追加)

モデルクラスを実装したトコロで、「モデル、どうやってテンプレートに渡すんだろう…?」という疑問が沸くと思います。
この疑問については、「テンプレートが生成するクラスと同名のクラスを定義」して、このクラスにモデルを持たせます。

C#では、「partial」をクラス定義に追加することで、1つのクラスを複数のファイルに分けて定義することができます。
この「partial」を使用して、テキストテンプレートが生成するコードとは別に同名のクラスを定義、このクラス…ソースコードの中にモデルを定義します。
具体的なコードは、以下!

public partial class RuntimeTextTemplate1
{
	protected List<DevEnv> _tableItems;

	public IEnumerable<DevEnv> TableItems
	{
		get
		{
			return this._tableItems;
		}
	}

	public RuntimeTextTemplate1() : base()
	{
		this._tableItems = new List<DevEnv>();
	}

	public void Add(DevEnv newItem)
	{
		this._tableItems.Add(newItem);
	}
}

テーブルに表示するデータの一覧をDevEnvのリストとして定義します。
プロパティは今回はgetterのみ定義し、対応するフィールドを返します。
また、DevEnvのリストがIEnumerableであり、外部から要素の追加ができません。
そのため、別途Add関数を実装しています。

3.2.5.mainの実装

最後は、main関数を実装します。
main関数で行うことは、

  1. RuntimeTextTemplateクラスを生成する
  2. テンプレートに対応するデータを設定する。
  3. 文字列に変換する

です。
今回は、以下のように実装しました。

class Program
{
	static void Main(string[] args)
	{
		var runtimeTemplate = new RuntimeTextTemplate1();
		runtimeTemplate.Add(new DevEnv("OS", "Windows10 Pro
ver.1903"));
		runtimeTemplate.Add(new DevEnv("CPU", "i7-8700"));
		runtimeTemplate.Add(new DevEnv("IDE", "VisualStudioCommunity2019
ver.16.5.1"));
		runtimeTemplate.Add(new DevEnv(".Net Framework", "4.7"));
		runtimeTemplate.Add(new DevEnv("アプリケーションの種類", "コンソールアプリケーション"));

		var content = runtimeTemplate.TransformText();

		Console.WriteLine(content);
	}
}

モデルをテンプレートに従って変換した結果は、変数contentに格納されます。
それを、WriteLine関数で表示します。

4.実行結果

これまで紹介したプログラムの実行すると、下図のようになります。
(ここに図を挿入)
目的の文字列が生成できていることが確認できます。

5.まとめ

今回は、C#のランタイムテキストテンプレートについて書きました。
必要なモデルデータを用意すれば、簡単にモデルからテキストを生成できることが分かりました。
今回は、HTMLのtableタグを例にしましたが、olタグやulタグに対応したテンプレートを用意することで、少ないコードの実装で対応可能です。
また、本エントリではHTMLタグを例にしましたが、他のテキストにも適用可能です。
そのあたりについては、また書きます。

ではっ!