かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

使い捨てのT4テンプレート活用法

ということで、MSDNのT4テンプレートのドキュメントを見たのは、ちょろっと使おうと思ったからです。

単調な繰り返しを伴うコードを書くのは苦痛でしかありません。私が尊敬する上司の人は、これを田植えと言ってました。確かに。大事なお仕事ではあるんだけど、めんどくさいことは否めない。そんなときにT4 テンプレートが使えないかどうか、ちょっと考えてみるといいかも?というのが今回の趣旨です。

使ってみよう

実際に今から、T4 テンプレートを使ってコードを生成してみようと思います。今回はMicrosoft.Win32.OpenFileDialogをラップする感じのTriggerActionを作りたいのですが、OpenFileDialogが持つプロパティをチェックすると・・・

こんなにある!!まぁ手書きでもいけないことはないけど、今後SaveFileDialogとかにも対応していくことを考えると苦行になるかもしれないのでT4 テンプレートでさくっと作ってしまおうという魂胆です。

ということで早速やってみます。WPFアプリケーションのプロジェクトを作ってGenerator.ttという名前でテキストテンプレートを作ります。中身を試行錯誤した挙句、こういう感じで依存プロパティを定義できるようになりました。

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".generated" #>
<#@ assembly name="PresentationCore" #>
<#@ assembly name="PresentationFramework" #>
<#@ assembly name="WindowsBase" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="System.Xaml" #>

<#@ import namespace="System" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="Microsoft.Win32" #>

<#
var props = typeof(OpenFileDialog).GetProperties();
foreach (var p in props)
{
	PropDp("OpenFileDialogAction", p);
}
#>

<#+
// 依存プロパティを作るお
void PropDp(string className, PropertyInfo p)
{
	var propertyType = p.PropertyType + (p.PropertyType.IsValueType ? "?" : "");
#>

public static readonly DependencyProperty <#= p.Name #>Property = 
	DependencyProperty.Register(
		"<#= p.Name #>",
		typeof(<#= propertyType #>),
		typeof(<#= className #>),
		new PropertyMetadata(null));

public <#= propertyType #> <#= p.Name #>
{
	get
	{
		return (<#= propertyType #>)this.GetValue(<#= p.Name #>Property);
	}
	
	set
	{
		this.SetValue(<#= p.Name #>Property, value);
	}
}
<#+
}
#>

生成されたコードをさくっとコピーしてOpenFileDialogActionに貼り付けます。コンパイルしてOK!かと思ったら1つのプロパティがIListのジェネリッククラスを使ってたので、そこでコンパイルがこけてしまいましたorz
生成されたコードは以下のようなものでした。

public static readonly DependencyProperty CustomPlacesProperty = 
	DependencyProperty.Register(
		"CustomPlaces",
		typeof(System.Collections.Generic.IList`1[Microsoft.Win32.FileDialogCustomPlace]),
		typeof(OpenFileDialogAction),
		new PropertyMetadata(null));

public System.Collections.Generic.IList`1[Microsoft.Win32.FileDialogCustomPlace] CustomPlaces
{
	get
	{
		return (System.Collections.Generic.IList`1[Microsoft.Win32.FileDialogCustomPlace])this.GetValue(CustomPlacesProperty);
	}
	
	set
	{
		this.SetValue(CustomPlacesProperty, value);
	}
}

これは、コンパイルできませんが汎用的なコードジェネレータを作るのが今回の目的ではないので、この部分は手書きでなおしました。とまぁ、こんな感じで使い捨てだけど、大量の単調なコードを書くことにT4 テンプレート使えるよ!!ということです。

何かの参考になれば・・・ということで今回はおしまい!