概要
T4 (Text Template Transfomration Toolkit) を利用して実行時テキスト生成をF#にて行う。 T4がサポートする言語はC#, VisualBasicのみだが、C#プロジェクトでテンプレートを作成し、別のF#プロジェクトからそれを参照するという形でF#でもT4を利用することが可能である。 以下にその手順を示す。
環境
- Windows 10 Pro バージョン 1909
- Visual Studio 2019 Community 16.5.4
- .Net Core 3.1.201
目次
手順
前準備
- F# .Net Core コンソールアプリのプロジェクトを作成しておく
- Visual StudioのT4拡張をインストールしておく
- 標準だとVisual Studioでttファイルを開いたときにコードハイライトが効かなくて見づらい
Visual Studioをダークテーマにしている場合、標準のバックグラウンドカラーではとても見づらくなるので変更する。
- メニューからツール→オプション
- tangible T4 Editor → Editor
- T4 Background Colorを選択し、カラーピッカーからお好みの色を選択する
テンプレート用C#プロジェクトを追加
- クラスライブラリ (.Net Core) (C#)で同じソリューション内にプロジェクトを追加する。
- F#のプロジェクトから上記のプロジェクトへの参照を追加しておく
テンプレートを追加
ランタイムテキストテンプレート
を選択して新規追加する。
テンプレートプロジェクトの .csproj
を直接開いて先程追加した .ttファイルの Generator
の項目を TextTemplatingFileGenerator
から TextTemplatingFilePreprocessor
に変更する。
<ItemGroup> <None Update="TestTemplate.tt"> <Generator>TextTemplatingFileGenerator</Generator> <LastGenOutput>TestTemplate.cs</LastGenOutput> </None> </ItemGroup> ↓↓↓ 変更後 ↓↓↓ <ItemGroup> <None Update="TestTemplate.tt"> <Generator>TextTemplatingFilePreprocessor</Generator> <LastGenOutput>TestTemplate.cs</LastGenOutput> </None> </ItemGroup>
テンプレートに渡すモデルを定義
public class TemplateModel { public string Name { get; } public int Age { get; } public TemplateModel(string name, int age) { Name = name; Age = age; } }
モデルを渡せるようにpartial classを定義
追加したテンプレートファイルと同名のクラスをpartial classとして定義し、先程追加したモデルをコンストラクタから受け取れるようにする。
public partial class TestTemplate { public TemplateModel Model { get; } public TestTemplate(TemplateModel model) { Model = model; } }
テンプレートファイルを修正
ジェネレータ部分のコードにフルパスでライン表示が出てしまうので linePragmas="false"
を指定する。
<#@ template language="C#" linePragmas="false" #>
上で定義したモデルを利用したテンプレートを記述する。
<#@ template language="C#" linePragmas="false" #> <#= Model.Name #> のねんれいは <#= Model.Age #> 歳です。
テンプレートプロジェクトに System.CodeDomを追加
このままテンプレートプロジェクトをビルドするとコンパイルエラーが発生するため System.CodeDom
を参照に追加する。
F#側で利用するコードを書く
- モデルに値を設定する
- templateクラスのコンストラクタにモデルを渡す
.TransformText()
メソッドで適用後のテンプレート文字列を取得
open System open Templates [<EntryPoint>] let main argv = let model = TemplateModel("シャミ子", 16) let template = TestTemplate(model) printfn "%s" <| template.TransformText() 0
実行結果