撰寫 T4 文字範本的方針
更新:2011 年 3 月
如果您要在 Visual Studio 中產生程式碼或其他應用程式資源,下列一般方針可能會派上用場。 但這些方針並不是死板的規則。
設計階段 T4 範本的方針
設計階段 T4 範本是一種可在設計階段於 Visual Studio 專案中產生程式碼的範本。 如需詳細資訊,請參閱使用 T4 文字範本在設計階段產生程式碼。
產生應用程式的可變層面。
對應用程式可能在建置專案時變更或將在應用程式不同版本間變更的層面來說,程式碼產生作業最為有用。 請將這些可變層面與非變異層面分開,讓您可以更輕鬆地判斷所需產生的部分。 例如,如果應用程式會提供網站,就可以將標準頁面提供功能與定義頁面之間巡覽路徑的邏輯分開。將一個或多個來源模型中的可變層面進行編碼。
模型是每個範本都會讀取的檔案或資料庫,目的是為所要產生之程式碼的可變部分取得特定值。 模型可能是資料庫、您自行設計的 XML 檔或 Domain-Specific Language。 通常,一個模型是用來在 Visual Studio 中產生許多檔案。每個檔案都是從個別的範本產生。您可以在專案中使用一個或多個模型。 例如,您可能為網頁之間的巡覽作業定義模型,又為網頁的配置定義不同的模型。
將模型著重於使用者的需要和詞彙,而非實作。
例如,在 Web 網站應用程式中,您預期模型會參考網頁和超連結。在理想狀況下,選擇適合模型所代表之資訊種類的表現形式。 例如,網站巡覽路徑的模型可以選用方塊和箭號組成的圖表。
測試產生的程式碼。
使用手動或自動化測試來確認產生的程式碼是否如使用者所要求般運作。 用來產生程式碼的模型應避免拿來產生測試。在某些情況下,可以直接在模型上執行一般測試。 例如,您可以撰寫測試,確認是否可以從其他網頁巡覽至此網站中每個網頁。
允許自訂程式碼:產生部分類別。
除了產生的程式碼之外,還允許以手動方式撰寫的程式碼。 讓程式碼產生配置能夠考量到所有可能發生的變化,是件非比尋常的工作。 因此,您只能期待增加或覆寫一部分產生的程式碼。 在使用 .NET 語言 (例如 Visual C# 或 Visual Basic) 產生資料的情況中,以下兩種策略特別有用:產生的類別必須是部分類別。 這樣才可以將內容加入至產生的程式碼。
類別應該成對產生,讓其中一個繼承另一個。 基底類別應該包含所有產生的方法和屬性,而衍生類別只應該包含建構函式。 這樣可讓您的手寫程式碼覆寫產生的任何方法。
在其他產生的語言 (例如 XML) 中,請使用 <#@include#> 指示詞簡單結合手寫內容與產生的內容。 在較為複雜的情況中,您可能還需要撰寫後置處理步驟,將產生的檔案與任何手寫的檔案結合在一起。
將常見的材料移入 Include 檔和執行階段範本
為避免類似的文字區塊和程式碼重複出現在多個範本中,請使用 <#@ include #> 指示詞。 如需詳細資訊,請參閱 T4 包含指示詞。您也可以在個別專案中建置執行階段範本,然後從設計階段範本加以呼叫。 若要這樣做,請使用 <#@ assembly #> 指示詞存取這個個別專案。 如需範例,請參閱 Gareth Jones 部落格文章:文字範本中的繼承(英文)。
考慮將大型程式碼區塊移入個別的組件。
如果您有大型程式碼區塊和類別功能區段,將這種程式碼的一部分移入您會在個別專案中編譯的方法,可能有所幫助。 您可以使用 <#@ assembly #> 指示詞存取範本中的程式碼。 如需詳細資訊,請參閱T4 組件指示詞。您可以將方法放入範本可繼承的抽象類別。 抽象類別必須繼承自 Microsoft.VisualStudio.TextTemplating.TextTransformation。 如需詳細資訊,請參閱T4 範本指示詞。
產生程式碼,而非組態檔
撰寫可變應用程式的其中一個方法就是撰寫可接受組態檔的泛型程式碼。 以這種方式撰寫的應用程式非常有彈性,並且在業務需要變更時,還可以重新設定組態而不必重新建置應用程式。 但是這種方法有一個缺點,就是應用程式的效能不像專屬的應用程式那樣好。 此外,其程式碼也比較不容易閱讀和維護,之所以如此,部分是因為程式碼必須不斷地處理泛型程度最大的型別。相反地,您可以將編譯前產生可變部分的應用程式設定為強型別。 這樣就可以手動撰寫程式碼,再將它與軟體的產生部分整合,讓工作變得更輕鬆也更可靠。
若要充分獲得程式碼產生作業的效益,請嘗試產生程式碼,而非組態檔。
使用 Generated Code 資料夾
將範本和產生的檔案放置在名為 Generated Code 的資料夾中,清楚表示不可直接編輯這些檔案。 如果您建立要覆寫或加入至產生之類別的自訂程式碼,請將這些類別放置在名為 Custom Code 的資料夾。 一般專案的結構看起來如下:MyProject Custom Code Class1.cs Class2.cs Generated Code Class1.tt Class1.cs Class2.tt Class2.cs AnotherClass.cs
執行階段 (前置處理過的) T4 範本的方針
將常見的材料移入繼承的範本
您可以使用繼承,在 T4 文字範本之間共用方法和文字區塊。 如需詳細資訊,請參閱T4 範本指示詞。您也可以使用包含執行階段範本的 Include 檔。
將大型程式碼主體移入部分類別。
每個執行階段範本都會產生與範本同名的部分類別定義。 您可以撰寫一個程式碼檔,其中包含相同類別的其他部分定義。 您可以透過這種方式將方法、欄位和建構函式加入類別中。 從範本中的程式碼區塊可以呼叫這些成員。這麼做的好處是撰寫程式碼更容易,因為可使用 IntelliSense。 而且,您還可以在展示與基礎邏輯之間達到更好的區分。
例如,於 MyReportText.tt:
The total is: <#= ComputeTotal() #>
於 MyReportText-Methods.cs:
private string ComputeTotal() { ... }
允許自訂程式碼:提供擴充點
考慮在 <#+ 類別功能區塊 #> 中產生虛擬方法。 這樣可以讓單一範本用於許多內容,而不需進行修改。 相對於修改範本,您可以建構衍生類別,這樣提供的額外邏輯最少。 衍生類別可以是一般程式碼或是執行階段範本。例如,於 MyStandardRunTimeTemplate.tt:
This page is copyright <#= CompanyName() #>. <#+ protected virtual string CompanyName() { return ""; } #>
於應用程式的程式碼:
class FabrikamTemplate : MyStandardRunTimeTemplate { protected override string CompanyName() { return "Fabrikam"; } } ... string PageToDisplay = new FabrikamTemplate().TextTransform();
所有 T4 範本的方針
區分從文字產生的資料收集
嘗試避免混用計算與文字區塊。 在每個文字範本中,使用第一個 <# 程式碼區塊 #> 設定變數並執行複雜的計算。 從第一個文字區塊一直到範本結尾或第一個 <#+ 類別功能區塊 #>,都避免使用長運算式,並且避免使用迴圈或條件式 (除非內含文字區塊)。 這麼做會讓範本更容易閱讀及維護。不要對 Include 檔使用 .tt
對 Include 檔使用其他副檔名,例如 .ttinclude。 只有對您想要處理為執行階段或設計階段文字範本的檔案,才使用 .tt。 在某些情況下,Visual Studio 會辨識出 .tt 檔案,並自動設定其屬性以進行處理。以固定的原型開始設計每個範本。
撰寫您要產生之程式碼或文字的範例,並確定其正確無誤。 接著將其副檔名變更為 .tt,然後讀取模型,逐步插入程式碼以修改內容。考慮使用具型別的模型。
雖然您可以為模型建立 XML 或資料庫結構描述,但是建立網域指定的語言 (Domain Specific Language,DSL) 可能會有所幫助。 DSL 的優點是會產生代表結構描述中每個節點的類別,並產生代表屬性 (Attribute) 的屬性 (Property)。 也就是說,您可以依照商務模型設計程式。 例如:Team Members: <# foreach (Person p in team.Members) { #> <#= p.Name #> <# } #>
考慮使用模型的圖表。
文字表格方式最能有效地呈現許多模型,而且在管理上相當簡單,尤其是在模型非常大的情況下。但是,就某些商務需求種類來看,闡明關聯性與工作流程的複雜集合是十分重要的,因此圖表是最適合的工具。 圖表的優點是易於與使用者和其他專案關係人進行討論。 從商務需求層級的模型產生程式碼,會讓程式碼在需求變更時更具彈性。
UML 類別和活動圖表通常最適合這些用途。 您也可以設計自己的圖表類型做為網域指定的語言 (DSL)。 程式碼都可以從 UML 和 DSL 產生。 如需詳細資訊,請參閱 模型化應用程式 和 模型化應用程式。
請參閱
概念
其他資源
變更記錄
日期 |
記錄 |
原因 |
---|---|---|
2011 年 3 月 |
整合意見 |
客戶回函。 |
2010 年 10 月 |
新主題排除現有材料。 |
資訊加強。 |