=============C#.Net 篇目錄==============
示例程式碼:示例程式碼_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/