撰寫 T4 文字範本的方針

如果您在 Visual Studio 中產生程式碼或其他應用程式資源,這些一般指導方針可能很有幫助。 其不是固定規則。

設計階段 T4 範本的指導方針

設計階段 T4 範本是在設計階段於 Visual Studio 專案中產生程式碼的範本。 如需詳細資訊,請參閱使用 T4 文字範本產生設計階段程式碼

產生應用程式的變數層面。

程式碼產生最適用於在專案期間可能會變更的應用程式層面,或將在不同版本應用程式之間變更的應用程式層面。 將這些可變層面與較不可變的層面分開,以便您可以更輕鬆地確定必須產生的內容。 例如,如果您的應用程式提供一個網站,請將提供功能的標準頁面與定義瀏覽路徑 (從某個頁面到另一個頁面) 的邏輯分開。

在一或多個來源模型中編碼可變層面。

模型是每個範本都會讀取的檔案或資料庫,為所要產生程式碼的變數組件取得特定值。 模型可以是資料庫、您自己設計的 XML 檔案、圖表或特定領域語言。 一般而言,一個模型用來在 Visual Studio 專案中產生許多檔案。 每個檔案都是從個別的範本產生。

您可以在專案中使用多個模型。 例如,您可以定義在網頁之間進行瀏覽的模型,以及用於頁面配置的個別模型。

將模型的焦點放在使用者的需求和詞彙上,而不是您的實作。

例如,在網站應用程式中,您會預期模型參考網頁和超連結。

在理想情況下,請選擇適合模型所代表資訊種類的呈現形式。 例如,網站的瀏覽路徑模型可能是方塊和箭號的圖表。

測試產生的程式碼。

使用手動或自動化測試,來驗證產生的程式碼是否按照使用者所要求運作。 避免從產生程式碼的同一模型產生測試。

在某些情況下,可以直接在模型上執行一般測試。 例如,您可以撰寫測試,確保可以透過從任何其他頁面進行瀏覽來到達網站中的每個頁面。

允許自訂程式碼:產生部分類別。

除了產生的程式碼之外,還允許您手動撰寫的程式碼。 程式碼產生配置能夠說明所有可能引發的變化並不常見。 因此,您應該預期要新增或覆寫某些產生的程式碼。 產生的材料若採用 .NET 語言,例如 C# 或 Visual Basic,則有兩種策略特別有用:

  • 產生的類別應該是部分的。 這可讓您將內容新增至產生的程式碼。

  • 類別應該成對產生,其中一個繼承自另一個類別。 基底類別應該包含所有產生的方法和屬性,而衍生類別應該只包含建構函式。 這可讓您手動撰寫的程式碼覆寫任何產生的方法。

在其他產生的語言 (例如 XML) 中,請使用 <#@include#> 指示詞,對手動撰寫和產生的內容進行簡單組合。 在更複雜的情況下,您可能必須撰寫後置處理步驟,以結合產生的檔案與任何手動撰寫的檔案。

將常用材料移至 Include 檔案或執行階段範本。

若要避免在多個範本中重複類似的文字和程式碼區塊,請使用 <#@ include #> 指示詞。 如需詳細資訊,請參閱 T4 Include 指示詞

您也可以在個別專案中建置執行階段文字範本,然後從設計階段範本呼叫這些文字範本。 若要這樣做,請使用 <#@ assembly #> 指示詞來存取個別的專案。

請考慮將大型程式碼區塊移至個別的組件。

如果您有大型程式碼區塊和類別功能區塊,將此程式碼的部分移至您在個別專案中編譯的方法,可能會很有用。 您可以使用 <#@ assembly #> 指示詞來存取範本中的程式碼。 如需詳細資訊,請參閱 T4 組件指示詞

您可以將方法置於範本可以繼承的抽象類別中。 抽象類別必須繼承自 Microsoft.VisualStudio.TextTemplating.TextTransformation。 如需詳細資訊,請參閱 T4 範本指示詞

產生程式碼,而非設定檔。

撰寫變數應用程式的一種方法是撰寫接受設定檔的泛型程式碼。 以這種方式撰寫的應用程式很有彈性,並可以在商務需求變更時重新設定,而無需重建應用程式。 不過,此方法的缺點是應用程式的效能低於更具體的應用程式。 此外,其程式碼將更難以讀取和維護,部分原因是其一律要處理最泛型型別。

相較之下,在編譯前產生變數組件的應用程式可以是強型別。 這可讓您更輕鬆且更可靠地撰寫手寫程式碼,並將其與軟體產生的組件整合。

若要取得程式碼產生的完整優點,請嘗試產生程式碼,而不是設定檔。

使用產生的程式碼資料夾。

將範本和產生的檔案置於名為 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 範本的指導方針

將資料收集與文字產生分開。

請嘗試避免混合計算和文字區塊。 在每個文字範本中,使用第一個 <# 程式碼區塊 #>,來設定變數並執行複雜計算。 從第一個文字區塊向下到範本結尾或第一個 <#+ 類別功能區塊 #>,避免長運算式,以及避免迴圈和條件,除非其包含文字區塊。 這種做法可讓範本更容易閱讀和維護。

不要將 .tt 用於 include 檔案。

將不同的副檔名 (例如 .ttinclude) 用於 include 檔案。 僅將 .tt 用於您想要當作執行階段或設計階段文字範本處理的檔案。 在某些情況下,Visual Studio 會辨識 .tt 檔案,並自動設定其屬性進行處理。

以固定原型的形式啟動每個範本。

撰寫您想要產生的程式碼或文字範例,並確定其正確無誤。 然後,將其副檔名變更為 .tt,並以累加方式插入藉由讀取模型來修改內容的程式碼。

考慮使用型別模型。

雖然您可以為模型建立 XML 或資料庫結構描述,但建立特定領域語言 (DSL) 可能會很有用。 DSL 的優點是其會產生類別來表示結構描述中的每個節點,以及產生屬性來表示屬性。 這表示您可以根據商務模型進行程式設計。 例如:

Team Members:
<# foreach (Person p in team.Members)
 { #>
    <#= p.Name #>
<# } #>

考慮為您的模型使用圖表。

許多模型會以文字資料表的形式進行最有效的呈現和簡單的管理,特別是當這些模型非常大時。

不過,對於某些種類的商務需求,釐清複雜的關聯性和工作流程集非常重要,而圖表是最適合的媒介。 圖表的優點是可以輕鬆與使用者和其他專案關係人一起討論。 藉由從商務需求層級的模型產生程式碼,您可以在需求變更時使程式碼更有彈性。

您也可以將自己的圖表類型設計為特定領域語言 (DSL)。 程式碼可從 UML 和 DSL 產生。 如需詳細資訊,請參閱分析架構並製作架構模型