示例代碼:示例代碼_for_真真理解T4_parameter指令.zip
本人最近在學習 T4 模板相關的知識,一些知料中文版的難找,所以翻翻老外的文章先譯出來分享給大家。這里有篇入門文章 《你必須懂的T4模板:淺入深出》
Visual Studio 2010 引入了一個新的 T4 指令:參數指令。這個參數提供一種在文本模板中定義輸入參數的標准方式。
語法
<#@ parameter name="…" type="…" #>
name 為參數指定名稱,參數名稱必須是 C# 或 VB 有效標示符。
type 為參數指定類型,參數類型必須包含完整的命名空間,eg:System.String 。也可以使用自定義類型,自定義類型的程序集必須使用 <#@ assembly #> 指令引入。
補充:CallContext 和LogicalCallContext
因為本文講到遠程調用的相關應用,譯者了解不多,所以在此補充這兩個概念。
1. CallContext 是類似於方法調用的線程本地存儲的專用集合對象,並提供對每個邏輯執行線程都唯一的數據槽。數據槽不在其他邏輯線程上的調用上下文之間共享。
2. LogicalCallContext 類是在對遠程應用程序域進行方法調用時使用的 CallContext 類的一個版本。當對另一個 AppDomain 中的對象進行遠程方法調用時,CallContext 類將生成一個與該遠程調用一起傳播的 LogicalCallContext。
讓CallContext實現跨線程傳播
CallContext API如下圖(注意:沒有提供構造函數):
也就是說,如果想讓CallContext的數據被自動傳遞到當目標線程,只能將其作為LogicalCallContext。我們有兩種方法將相應的數據存儲為LogicalCallContext:
1. 調用CallContext的靜態方法LogicalSetData 。
2. 讓 CallContext 傳遞的對象實現 ILogicalThreadAffinative 接口。實現 ILogicalThreadAffinative 接口並存儲在 CallContext 中的對象會自動隨 LogicalCallContext 傳播到 AppDomain 外部。
欲知更多,請參考:如何實現對上下文(Context)數據的統一管理
使用
在模板轉換期間,參數可做為只讀的強類型屬性在代碼中使用(只生成屬性的 get 訪問器)。
MyTemplate.tt (設計時模板)
<#@template language="C#"#>
<#@Parameter Name="MyParameter" Type="System.String"#>
Parameter in statement block: <# Write(MyParameter == null ? "null" : MyParameter); #>
調用輸出字符串:
Parameter in statement block: null
參數值既可以由遠程的 CallContext提供,也可以由 Session 字典提供。典型的,模板參數會被應用在 T4 引擎實例或依賴於標准的 ITextTemplating 服務的 Visual Studio擴展中。雖然 Visual Studio 擴展是一個令人着迷的主題,但已不屬於本文討論的范圍。而本文重點將說明使用模板代碼本身的技術傳遞參數值。
CallContext
CallContext 允許你定義全局變量,變量只能在單個線程中訪問,也稱為“線程局部變量”。“線程局部變量”雖然表面上像存儲在本地 Windows 的 CallContext ,但實際上是遠程調用創建,無論是通過網絡還是在 AppDomain 域之間傳遞 CallContext ,CallContext 將生成一個與該遠程調用一起傳播的 LogicalCallContext 。換句話說,CallContext允許定義的“線程局部變量”用於遠程調用。
在 Visual Studio 中 T4 模板通常執行在單獨的應用程序域中,即可以通過定期卸載應用程序域來釋放內存。因此,遠程的 CallContext 是指定模板參數值的好方法。下面的示例說明如何使用 CallContext 傳遞參數值。
CallContextTemplate.tt
<#@template debug="false" hostspecific="True" language="C#"#>
<#@output extension=".txt"#>
<#@import namespace="System.IO"#>
<#@import namespace="System.Runtime.Remoting.Messaging"#>
<#@import namespace="Microsoft.VisualStudio.TextTemplating"#>
<#
string templateFile = this.Host.ResolvePath("MyTemplate.tt");
string templateContent = File.ReadAllText(templateFile);
CallContext.LogicalSetData("MyParameter", "CallContextVall");
Engine engin = newEngine();
// 代碼調用執行 文本模板 文件
stringgeneratedContent
= engin.ProcessTemplate(templateContent, this.Host);
CallContext.FreeNamedDataSlot("MyParameter");
this.Write(generatedContent);
#>
輸出:
Parameter in statement block: CallContextVall
文本轉換會話
在 Visual Studio 2010 中, T4 允許你像使用在 ASP.NET 中訪問 Session 一樣的方式訪問 “文本轉換會話”。文本轉換會話允許你為特定模板定義全局變量。 會話變量能從當前的轉換模板宿主傳遞到任意模板並且可以被用於模板參數值。
SessionTemplate.tt
<#@template debug="false" hostspecific="True" language="C#"#>
<#@output extension=".txt"#>
<#@Import Namespace="System.IO"#>
<#@Import Namespace="Microsoft.VisualStudio.TextTemplating"#>
<#
string templateFile = this.Host.ResolvePath("MyTemplate.tt");
string templateContent = File.ReadAllText(templateFile);
TextTemplatingSession session = newTextTemplatingSession();
session["MyParameter"] = "SessionValue";
var sessionHost = (ITextTemplatingSessionHost)this.Host;
sessionHost.Session = session;
Engine engine = newEngine();
string generatedContent = engine.ProcessTemplate(templateContent, this.Host);
this.Write(generatedContent);
#>
輸出:
Parameter in statement block: SessionValue
在后台
T4 引擎為模板為每個參數指令生成一個私有的、只讀的屬性。自動生成的轉換類類似如下代碼:
MyTemplate.tt (運行時模板)
public partial class MyTemplate : TextTransformation
{
private string _MyParameterField;
private string MyParameter
{
get { return this._MyParameterField; } // 只讀,私有屬性
}
public override string TransformText()
{
this.GenerationEnvironment = null;
this.Write("\r\nParameter in statement block: ");
Write(MyParameter == null ? "null" : MyParameter);
return this.GenerationEnvironment.ToString();
}
// …
}
注意 MyParameter 屬性是私有字段,這個字段被生成類中重寫的 Initialize() 方法進行初始化,Initialize() 方法在 Transform() 方法之前被執行。
正如您所看到的該模板將首先嘗試從 Session 字典中檢索的參數值,如果Session無此鍵則會嘗試 CallContext 。
作者: Oleg Sych
原文鏈接:http://www.olegsych.com/2010/05/t4-parameter-directive/