你必須懂的 T4 模板:深刻淺出

=============C#.Net 篇目錄==============html

示例代碼:示例代碼__你必須懂的T4模板:淺入深出.rar程序員

 

(一)什麼是T4模板?數據庫

T4,即4個T開頭的英文字母組合:Text Template Transformation Toolkit。緩存

T4文本模板,即一種自定義規則的代碼生成器。根據業務模型可生成任何形式的文本文件或供程序調用的字符串。(模型以適合於應用程序域的形式包含信息,而且能夠在應用程序的生存期更改)app

 

VS自己只提供一套基於T4引擎的代碼生成的執行環境,由下面程序集構成:編輯器

Microsoft.VisualStudio.TextTemplating.10.0.dllide

Microsoft.VisualStudio.TextTemplating.Interfaces.10.0.dll函數

Microsoft.VisualStudio.TextTemplating.Modeling.10.0.dll工具

Microsoft.VisualStudio.TextTemplating.VSHost.10.0.dll學習

 

便利工具:

一、  T4Toolbox.msi(CodePlex上開源的工具)

a)         提供一些能夠直接使用的代碼生成器,好比Enum SQL View、AzMan wrapper、LINQ to SQL classes、LINQ to SQL schema和Entity Framework DAL等。

b)         提供一些基於T4方面的VS的擴展:當你安裝以後,在「Add New Item」對話框中就會多出一個命名爲「Code Generation」的類別,其中包括若干文件模板。

二、  T4 模板編輯器(eg:支持代碼着色、智能提示)

a)         tangible T4 Editor (下載)

b)         Visual T4 (下載)

    固然咱們也能夠經過VS2010中新增的擴展管理器(Extension Manager)來添加Vs擴展插件。擴展管理器(Extension Manager),這和Eclipse/Netbeans有些類似,用戶能夠直接在IDE中從Visual Studio 庫(Visual Studio Gallery)找到並下載擴展。經過VS的菜單Tools->Extension Manager,這裏你能夠添加,刪除已經安裝的VS的擴展插件。打開界面以下:

 

 

筆者在學習 T4 的時候使用過上面兩個 T4 模板編輯器。稍做幾點對比:

a)         tangible T4 Editor可選擇安裝內嵌的 UML 模板模型

       

b)         對於不是經常使用的dll( eg:EnvDTE.dll ),tangible T4 Editor免費版和 Visual T4 都不支持導航,而且所報的提示頁不同

tangible T4 Editor免費版中提示以下:

 

 

Visual T4中則直接提示:

 

可是在 Visual T4 中,咱們能夠經過在程序集中引入 EnvDTE.dll 解決此錯誤的提示(完成開發後可移除程序集引用),而且還能完美的得到該程序集的智能提示功能,以下圖所示:

 

         同時咱們也能夠看到 Visual T4 中代碼着色也更加貼近 VS (藍色字體標註對象)。

小結:

  1. 就「代碼着色」和「智能提示」方面Visual T4 工具表現更完美(前提是必須主動在項目中引入對應程序集),但目前最新版本存在縮進問題實在惋惜,悲憤中等更新。.
  2. 可能你還想要tangible T4 Editor提供的 UML 模板模型,呵呵……如今我本機同時裝了這兩款 T4編輯器,暫時還沒發現衝突。

 

(二)T4基本結構

T4模板能夠分爲:指令塊、文本塊、控制塊。

  1. 指令塊 - 向文本模板化引擎提供關於如何生成轉換代碼和輸出文件的通常指令。
  2. 文本塊 - 直接複製到輸出的內容。
  3. 控制塊 - 向文本插入可變值並控制文本的條件或重複部件的程序代碼,不能在控制塊中嵌套控制塊。

n  指令塊

6個指令<#@ template #>、<#@ parameter#>、<#@ assembly #>、<#@ import #>、<#@ include #>、<#@ output #>、

其中, output 和 assembly 只能用在設計時模板。

1)         T4 模板指令

<#@ template [language="C#"] [hostspecific="true"] [debug="true"] [culture="code"] [inherits="templateBaseClass"] [compilerOptions="options"] #>

這裏只說明下 inherits 屬性,其他屬性在本文更合適的地方有進行說明。

inherits             

指定模板的程序代碼繼承自另外一個類,該基類能夠是由其餘模板生成。

1)         運行時(預處理過的)文本模板中的繼承

若是不指定 inherits 特性,則會從您的文本模板生成基類和派生類。指定 inherits 特性時,僅生成派生類。

2)         設計時文本模板中的繼承

設計時模板會生成任何類型的「文本文件」,此文件將組成 Visual Studio 項目的一部分。T4 模板引擎首先要將模板轉換爲中間程序代碼文件,中間代碼文件將寫入您的 %TEMP% (環境變量) 目錄。默認該生成的中間代碼繼承自 Microsoft.VisualStudio.TextTemplating.TextTransformation 類,但你也可根據需求使用 inherits 特性指定派生於 TextTransformation 類的任何基類。

                   模板引擎生成轉換類更詳細的請參考本文後面的 什麼時候編譯,編譯過程  節。

 

2)         T4 參數指令

<#@ parameter type="Full.TypeName" name="ParameterName" #>

在 Visual Studio 文本模板中,parameter 指令聲明模板代碼中從自外部上下文傳入的值初始化的屬性。能夠聲明任何遠程類型的參數。也就是說,類型必須使用SerializableAttribute進行聲明,或者必須從MarshalByRefObject派生。這樣能夠將參數值傳遞到在其中處理模板的AppDomain中。

如何使用及內部運做機制請查看個人另外一篇文章 《(譯)理解 T4 模板:<#@ parameter #> 指令》 

 

3)         T4 導入指令

<#@ import namespace="namespace" #>

 

4)         T4 包含指令

<#@ include file="filePath" #>

a)         爲了增長代碼的可維護性,將公用函數作爲類功能塊(<#+ 類功能控制塊 #>)存放在單獨的文件中,該文件能夠被 <#@include#> 到一個或多個模板文件中。

b)         對於包含文件,文件擴展名使用 .ttinclude可讀性更好。(以區分後綴爲 .tt的運行時或設計時文本模板)

 

5)         T4 輸出指令

<#@ output extension=".fileNameExtension" [encoding="encoding"] #>

運行時(預處理)文本模板中不須要 output 指令。應用程序經過調用TextTransform() 來獲取已生成的字符串。

 

6)         T4 程序集指令

<#@ assembly name="[assembly strong name|assembly file name]" #>

在預處理文本模板中,assembly 指令無效。改成在 Visual Studio 項目中直接「添加引用」。

程序集名稱應爲如下各項之一:

  1. GAC 中程序集的強名稱,例如 System.Xml.dll。還可使用長名稱,例如 name="System.Xml, Version=4.0.0.0, Culture=neutral,PublicKeyToken=b77……"。
  2. 程序集的絕對路徑

可使用 $(variableName) 語法引用 Visual Studio 或MSBuild變量(如 $(SolutionDir)),以及使用 %VariableName% 來引用環境變量。

                   另,給出一些經常使用的 【生成命令和屬性的宏】

$(ConfigurationName)

當前項目配置的名稱(如「Debug」)。

$(PlatformName)

當前項目平臺的名稱(如「Win32」)。

$(ProjectName)

項目的基本名稱。

$(TargetDir)

生成的主輸出文件的目錄(定義爲驅動器 + 路徑);包括尾部的反斜槓「\」。

$(TargetName)

生成的主輸出文件的基本名稱。

$(FrameworkDir)

安裝 .NET Framework 的目錄。

$(FrameworkVersion)

Visual Studio 使用的 .NET Framework 版本。

$(WebDeployPath)

從 Web 部署根到項目輸出所屬於的位置的相對路徑。返回與RelativePath相同的值。

$(WebDeployRoot)

指向<localhost>位置的絕對路徑。例如,c:\inetpub\wwwroot。

 

n  控制塊

有三種類型的控制塊,根據其左括號對它們進行區分:

1.      <# 標準控制塊 #>                            能夠包含語句。

2.      <#= 表達式控制塊 #>            將一個能夠計算爲字符串的表達式括起來,用於提供要寫入「輸出」文件的字符串的代碼。

3.      <#+ 類功能控制塊 #>            可使用類功能控制塊向文本模板添加方法、屬性、字段甚至是嵌套類。必須做爲文件中的最後一個塊顯示,或者用<#@ include #>引入外部文件。

注意:

1)         始終使用 {...}花括號來包含內嵌的嵌套語句,不然會報錯。(哪怕花括號中只有一句代碼)

2)         控制塊不能互相嵌套。必須先終止以前的控制塊,而後才能打開另外一個。

 

(三)設計時模板和運行時模板

T4文本模板分爲:設計時模板和運行時模板

n  添加模板

  1. 設計時模板(文本模板)

優點:當需求變化時,能夠根據業務需求調整模型(輸入),按照指定規則將「模型」生成任何類型的「文本文件」,例如:網頁、資源文件或任何語言的程序源代碼。(模型:是描述應用程序特定方面的數據源。它能夠是任何形式、任何類型的文件或數據庫。如:數據庫、配置文件、UML 模型、DSL 模型或其餘源)

a)         VS中新建文件——常規——文本模板。(如圖)

 

該模板文件中已包含下列指令:

<#@ template debug="false" hostspecific="false" language="C#" #>

<#@ output extension=".txt" #>

b)         或則,添加「純文本文件」並設置下圖屬性,加入相關指令。(後綴推薦改成標準的 *.tt)

設計時模板: TextTemplatingFileGenerator

 

  1. 運行時模板(已預處理的文本模板)   

優點:當需求變化時,能夠根據業務需求調整模型(輸入),在運行時按照指定規則將「模型」生成爲「文本字符串」。

  1. VS中新建文件——常規——已預處理的文本模板。

該模板文件包含指令:<#@ template language="C#" #>

  1. 或則,添加「純文本文件」並設置相應屬性,加入相關指令。

運行時模板:TextTemplatingFilePreprocessor

 

n  什麼時候編譯,編譯過程

  1. 什麼時候編譯

在下列任何一種狀況下,將執行模板,同時生成附屬文件,生成的文件將做爲項目的一部分編譯。(屬性框----生成操做:編譯)

1)         編輯模板(模板有異動且沒有被保存),當前編輯模板失去焦點。

2)         保存模板。

3)         在「解決方案資源管理器」工具欄中單擊「轉換全部模板」。轉換解決方案中的全部模板。

      

4)         右擊「解決方案資源管理器」中的一個或多個模板文件,而後選擇「運行自定義工具」。

  1. 編譯過程

設計時模板

1)         文本模板轉換引擎將「文本模板」轉換爲可執行的cs代碼——「轉換類」。轉換類(*.cs)存於臨時目錄下。(臨時目錄在「環境變量」中設置:右鍵「個人電腦」—「屬性」—「高級系統設置」—「高級」選項卡中「環境變量」—TEMP變量)

命名空間:Microsoft.VisualStudio.TextTemplating + 隨機碼

基類:Microsoft.VisualStudio.TextTemplating.TextTransformation

類名:GeneratedTextTransformation

 

2)         引擎編譯生成的「轉換類」生成dll,dll存於臨時目錄下。具體是哪一個dll能夠在模板的「調試環境」下使用System.Reflection.Assembly.GetExecutingAssembly();獲取。

3)         執行已編譯的轉換類,生成「文件」。新文件會在「解決方案資源管理器」中出如今文本模板文件下。

 

運行時模板

1)         運行時模板沒有<#@ output #>指令,文本模板引擎將「運行時模板」直接編譯爲cs文件,做爲項目的一部分編譯。新文件會在「解決方案資源管理器」中出如今文本模板文件下。

命名空間:默認爲所屬程序集的命名空間

基類:模板文件名 + Base 

類名:模板文件名(PreTextTemplateTest.tt)——注意是「分部類」

 

2)         生成的代碼文件隨着項目一塊兒編譯,並可在應用程序中經過調用生成類中的TransformText() 方法輸出「文本字符串」。

 

另外,若要在特定命名空間中放置模板轉換生成的類,需設置模板文件的「自定義工具命名空間」屬性。

 

  1. 注意事項

1)         控制塊使用陷進

TransformText() 方法是由模板引擎將模板中的全部「控制塊」代碼(包括「包含的模板」)組合生成。因此在使用控制塊時應注意如下幾點:

a)         語言:只能使用一種語言。

b)         局部變量:確保局部變量的名稱不會衝突。

2)         文本模板在單獨的AppDomain中運行

請注意,文本模板在與主應用程序分開的AppDomain中運行。在大多數狀況下這並不重要,但在某些複雜的狀況下您可能會發現一些限制。例如,若是要從單獨的服務將數據傳入模板或從中傳出數據,則該服務必須提供可序列化的 API。

 

(四)技巧

l  快速編寫模板

以生成文件爲原型,而後逐步插入用於改變結果的控制塊。

 

l  T4文本模板的斷點調試

  1. 註冊表:設置DbgJITDebugLaunchSetting值爲 2。

(x86系統): HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework

(x64 系統): HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework

  1. 爲template指令添加debug="true"特性:<#@ template debug="true"#>
    1. 命令:

<# System.Diagnostics.Debugger.Launch();#>                  在模板執行到特定點啓動調試器。若是用Debugger.Break()啓動調試器在調試完後會致使 VS 奔潰。

<#System.Diagnostics.Debugger.Break();#>                     啓動調試器後,使用此命令在後續特定點處再次進入調試模式,至關於斷點。

使用方法:必須使用「Debugger.Launch()」命令啓動調試器(以下圖,啓動新實例或使用已存在的VS附加。注意,若此處點擊取消則將關閉當前IDE),調試完後能夠不用中斷調試,不影響模板編輯,當再次編譯模板時若是存在「Debugger.Break()」命令則自動進入調試模式。

 

 

l  向模板傳遞參數的兩種方法

  1. 使用 <#@ parameter#> 指令引入參數,由模板引擎生成屬性訪問代碼。詳細請看 《(譯)理解 T4 模板:<#@ parameter #> 指令》 
  2. 在構造函數中傳遞參數。只適用於運行時模板,此種模板生成的代碼以分部類的形式編寫。能夠在項目的另外一個文件中建立同一個類的其餘部分,該文件能夠包含一個帶參數的構造函數、若干屬性和函數,在調用 TransformText() 實例方法前進行初始化。

 

l  使用模板繼承共享內容

能夠經過編寫基類模板(能夠是抽象模板)在文本模板之間共享內容。使用<@#template#> 指令的 inherits 特性指定基類。

 

l  運行時調用設計時模板返回字符串

調用 Microsoft.VisualStudio.TextTemplating.Engine 的 ProcessTemplate 方法。

publicstring ProcessTemplate(

     string content,

     ITextTemplatingEngineHost host

)

        content    參數指定文本模板的內容,eg: 使用System.IO.File.ReadAllText(Path) 進行讀取

host        參數指定的宿主,必須是實現 ITextTemplatingEngineHost 的類。這是由模板引擎回調的。宿主必須能記錄錯誤、解析對程序集和包含文件的引用、提供可在其中執行模板的應用程序域併爲每條指令調用相應的處理器。

 

演練:建立自定義文本模板宿主

 

(五)經常使用方法

n  模板基類提供的方法

設計時模板繼承TextTransformation抽象類

 

 

運行時模板默認繼承自動生成的基類

 

  1. Write() 和WriteLine() 方法

寫入目的輸出文本的三種方式:

a)         文本塊

b)         表達式控制塊:      <#= 變量 #>

c)         標準控制塊:           <# Write() | WriteLine() #>,由於控制塊不能嵌套,因此此種方式比<#= 變量 #>書寫更優雅。

  1. 輸出文本縮進設置

可使用縮進方法設置文本模板輸出的格式。

a)         PushIndent(string indent)         添加指定格式,內部會將字符長度加入到緩存變量indentLengths列表(List<int>)。

b)         PopIndent()                 以「堆棧(先進後出)」形式移除格式,內部按indentLengths列表中存的字符長度進行移除。

c)         ClearIndent()              刪除全部縮進。

注意:格式用完後要注意清除,不然可能出現模板中的空行會生成 Write(「\r\n」) 中間代碼,最終形成將縮進的格式錯誤輸出到了目的文件。

Eg:

 

  1. 錯誤報告

若要在 Visual Studio 錯誤窗口中放置錯誤消息和警告消息,可使用如下方法:

<# this.Error("An error message"); #>

<# Warning("A warning message"); #>

 

n  使用執行模板的主機(例如 Visual Studio)公開的方法和屬性。這適用於常規文本模板,而不是預處理過的文本模板。

首先,給 template 指令添加hostspecific="true" 特性,以便使用this.Host對象。

(Microsoft.VisualStudio.TextTemplating.ITextTemplatingEngineHost)接口提供方法

 

  1. 使用this.Host.ResolvePath()從相對路徑名打開文件
  2. 使用LogErrors() 顯示錯誤消息,以下圖:

       

  1. 使用 Visual Studio 中提供的服務(加載EnvDTE.dll )

EnvDTE是組件包裝 COM 程式庫,其中包含了 Visual Studio 核心 Automation 的物件及成員。

引入 EnvDTE.dll 組件後應按下圖「屬性」進行設置:

 

示例:

<#@ assembly name="EnvDTE" #>

<#

IServiceProvider serviceProvider = (IServiceProvider)this.Host;

EnvDTE.DTEdte = (EnvDTE.DTE) serviceProvider.GetService(typeof(EnvDTE.DTE));

dte.Solution.SaveAs("C:\\backup_Solution");

#>

 

程序員的基礎教程:菜鳥程序員

相關文章
相關標籤/搜索