テキストテンプレート変換ツールキット(T4):Visual Studioのコードジェネレーター

こんにちは、Habr!



今日はルーチンについてお話します。 時々、すべてのプログラマーは多くの退屈でボリュームのあるステレオタイプの仕事をしなければなりません。彼は常にそれを自動化したいのですが、彼の手は届きません。 これは、 コード生成の助けを借りて私の人生を簡素化するあまり知られていない方法の1つです。今日、アフィリエイトのコミュニティに伝えたいと思います。 このメソッドは、 Text Template Transformation Toolkitまたは単にT4として知られています。



T4の知識



タスクの例



次の状況を想像してください。有限状態マシンを記述する必要があります。 信じられないほど曲がって実装されますが、この例は説明に非常に適しています。 実装中、マシンの中心は1つのパラメーターを受け取る関数になりました-現在の状態で、その値に応じて特定のアクションを実行します。 列挙型でマシンのすべての可能な状態を事前に説明しましたが、モニターを見るのは悲しいです:分割画面で巨大なスイッチを説明する必要がありますが、どうすればいいですか...



タスクを具体化して、マシンに3つの状態があり(43の状態があると想像してください-これが何らかのWinAPIメッセージだとしましょう)、enumは次のようになります。



enum State

{

Alive,

Dead,

Schrodinger

}






タスクは、T4を使用して次のコードを生成するテンプレートを作成することです。



void Select(State state)

{

switch (state)

{

case State.Alive:

// code here

break ;

case State.Dead:

// code here

break ;

case State.Schrodinger:

// code here

break ;

default :

// code here

break ;

}

}







ソリューションのレシピ



以下、Visual Studio 2005/2008/2010がインストールされていることを暗黙的に想定しています。 カスタムプロジェクトで、拡張子が* .ttの新しいファイル、たとえばSwitch.ttを追加します。 この拡張子はテンプレートファイルの標準であり、Studioによって自動的に認識されます。 ソリューションエクスプローラーでは、まだ空のSwitch.csファイルを含む別のノードが自動的に追加されていることに注意してください。 次に、生成の結果が表示されます。

だから、最初に-レシピ、次に説明。 空のSwitch.ttファイルに、次のテキストを貼り付けます。

<#@ template language="C#v3.5" debug="True" #>

<#@ output extension="cs" #>

void Select(State state)

{

switch (state)

{

<# foreach (string Value in Enum.GetNames(typeof(State))) { #>

case State.<#= Value #>:

// code here

break;

<# } #>

default:

// code here

break;

}

}

<#+

enum State

{

Alive,

Dead,

Schrodinger

}

#>






Ctrl + Sを押した後、Switch.csを見るだけで必要なテキストが表示されます。



この魔法はどのように機能しますか?



テンプレートテキストを詳しく見てください。 T4は宣言型のスタイルを使用しているため、ASP.NETスタイルのタグはコードのあらゆる場所で使用されます。 そのため、テンプレートファイルに含まれるすべてのコードは、次の5つのタイプに分類できます。



テンプレートが作成される原理を完全に理解するために、舞台裏を確認する必要があります。T4が.ttファイルのテキストをどのように解釈するかを正確に調べるためです。 これを行うには、%TEMP%フォルダーで最後に作成された.csファイルを見つけます。 多数の#lineを捨ててコードをフォーマットすると、この場合は次のようになります。



namespace Microsoft. VisualStudio . TextTemplatingFE5E01C975766D0E3C1DD071A5BFF52A {

using System ;

using Microsoft.VisualStudio.TextTemplating.VSHost ;



public class GeneratedTextTransformation : Microsoft. VisualStudio . TextTemplating . TextTransformation {

public override string TransformText ( ) {

try {

this . Write ( "void Select(State state) \r \n { \r \n \t switch (state) \r \n \t { \r \n " ) ;

foreach ( string Value in Enum . GetNames ( typeof ( State ) ) ) {

this . Write ( " \t \t case State." ) ;

this . Write ( Microsoft. VisualStudio . TextTemplating . ToStringHelper . ToStringWithCulture ( Value ) ) ;

this . Write ( ": \r \n \t \t \t // code here \r \n \t \t \t break; \r \n " ) ;

}

this . Write ( " \t \t default: \r \n \t \t \t // code here \r \n \t \t \t break; \r \n \t } \r \n } \r \n " ) ;

}

catch ( System . Exception e ) {

System. CodeDom . Compiler . CompilerError error = new System. CodeDom . Compiler . CompilerError ( ) ;

error. ErrorText = e. ToString ( ) ;

error. FileName = "C: \\ Users \\ Alex \\ Documents \\ Visual Studio 2008 \\ Projects \\ T4Article \\ T4Article \\ Switch.tt" + "" ;

this . Errors . Add ( error ) ;

}

return this . GenerationEnvironment . ToString ( ) ;

}

enum State

{

Alive,

Dead,

Schrodinger

}

}

}






ご覧のとおり、T4はMicrosoft.VisualStudio.TextTemplating.TextTransformation



の後継クラスを自動的に作成し、その中で単一のTransformText()



メソッドをオーバーライドします。このメソッドは、出力ファイルのテキストを部分的に形成します。 ソーステンプレートのコードブロックはメソッドコードの一部になり、 this.Write



を呼び出すことでテキストブロックが出力テキストに追加されます。 同様に、式のブロックが解釈されます。 クラスプロパティのブロックに関しては、 TransformText()



メソッドコードで参照できるように、後でジェネレータクラスに追加される情報を表すことが明らかになりました。 この例では、これはState列挙型の定義ですが、ジェネレーターがアクティブに使用する関数など、 <#+ #>



内で完全に記述できます。



ジェネレーターはC#で記述されています。 なんで? 注文したからです。 ディレクティブ<#@ template language="C#v3.5" #>



は、コード、クラスプロパティ、および式のブロックで使用されるプログラミング言語を定義します。 現時点では、可能な値は"C#"



"VB"



"C#v3.5"



"VBv3.5"





また、テンプレートテキストに<#@ template debug="True" #>



が示されていない場合、%TEMP%の関連<#@ template debug="True" #>



情報だけでなく、ジェネレータのトレースも見つかりません。 。



指令

残りのディレクティブとパラメーターはあまり頻繁に使用されないので、画面スペースをそれらに費やす必要はないと思います:)好奇心people盛な人は、ポストスクリプトのドキュメントへの必要なリンクをすべて見つけることができます。



特別な何か



TextTransformation



テンプレートの分析を実行し、ジェネレーターを作成する際に、Microsoftのスタッフは非常に不経済になるために、自身の実現した機会を利用したことを認めなければなりません。 たとえば、コードIDを取得します。 上記のジェネレーターは読むのに問題があります-これらすべての無限の推論「\ t \ t \ t \ t」から目がはじけます。

しかし、必要なのは単純なPushIndent("\t")



関数PushIndent("\t")



でした。 彼女は一般的な接頭辞に新しい部分を追加し、それが各書き込みに追加されます。 ごPopIndent()



、ペア関数PopIndent()



は、プレフィックスから最後に追加された部分を削除します。

CurrentIndent



プロパティとClearIndent()



メソッドもあります。 ちょうど情報のために:)



改行を使用した同様の状況-文字列リテラルで「\ r \ n」を生成する代わりに、WriteをWriteLineに置き換えることができます。 もちろん、現在のプラットフォーム内で。



また、 Warning()



およびError()



メソッドに言及しても害はありません。 ジェネレータコードで呼び出されると、警告またはエラーが発生し、テンプレートを解釈しようとするとエラーリストに表示されます。 予期しない状況でコードのブロックを使用することは非常に便利です。



プロの例



前のタスクによると、多くの退屈なC#コードを記述しないように、T4テンプレートは小さな即興のタスクにのみ使用することが有益であると思われるかもしれません。 種類はありません。 鮮明な例を示します。これは、Tangibleコレクションのテンプレートです。これは、指定した画像フォルダーの画像のギャラリーを含む単純なHTMLページを作成します。

最も興味深いのは、長くなく、読みやすく、開発者のニーズに合わせて変更できることです。

余分なテキストブロックで記事を損なわないように、pastebinに投稿しました



T4のもの



結論として、いくつかの便利なリンク。

記事の冒頭で、MSDN T4ドキュメントへのリンクが提供されました。 ただし、これはジェネレーターの構文と機能の最も完全な説明ですが、実用的な例はありません。



Oleg Sychのブログは、有用なT4情報の保管庫です。 ここでは、テンプレートをデバッグおよび変更する方法について詳しく学ぶことができ、多くの既製の例(ストアドプロシージャ、LINQおよびEntity Frameworkクラス、構成、MSBuildおよびWiXスクリプトなど)、およびより「高度な」ものに関するストーリーがあります。この記事に収まらないテンプレートの機能。 おそらく、次の記事の後半で、この情報をhabraの視聴者に適合させるでしょう。



T4ツールボックス -Visual Studioで「新しいファイル」T4を作成するための既製のテンプレートのセット。



Tangible Engineering T4 Editorは、IntelliSenseを備えた使いやすいバックライトエディターで、Visual Studioのプラグインとして実装されています。 有料版と無料版の2つのエディションがあります。 個人的には、無料版の可能性で十分です。

Tangibleよりも便利なもの-既製のテンプレートの優れたギャラリーがあります。



Clarius ConsultingのT4 Editorは、スタジオプラグインとしてのT4テンプレート用のもう1つのエディターです。 無料版の機能がわずかに削減されている点でのみ、以前のものと異なります。



おわりに



このf話の教訓は次のとおりです。もし運命が単調で退屈な仕事の必然性に直面したならば、あなたは決して助けを拒否すべきではありません。 特に-コンピューターの助けから。

コード生成で頑張ってください! :)




All Articles