前幾節已完成狀態機設計器,可視覺化設計狀態流程。但若止於「畫圖」,不如直接用 UML 工具。模型驅動開發 (MDD) 的核心價值在於從模型自動生成程式碼。本節示範結合 T4 (Text Template Transformation Toolkit) 實現程式碼生成。
VS 未內建 T4 編輯器,建議先安裝免費的 T4 Editor Community Edition 獲得語法醒目提示。
啟動專案,Debugging 專案下有 LanguageSmReport.tt:
<#@ Import Namespace="System" #>
<#@ template inherits="Microsoft.VisualStudio.TextTemplating.VSHost.ModelingTextTransformation" language="C#" #>
<#@ output extension=".txt" #>
<#@ LanguageSm processor="LanguageSmDirectiveProcessor" requires="fileName='Test.mydsl5'" #>
<#
foreach (State state in StateMachine.States) {
#>
<#= state.Name #>
<#
}
#>
執行「執行自訂工具」產生 LanguageSmReport.txt:
Draft
NewOrder
Cancelled
Confirmed
對應的模型圖:

<#@ Import ... #>:引用命名空間,對應 DLL 需加入專案參考。<#@ template inherits="..." language="C#" #>:指定基類 ModelingTextTransformation,語言可用 C#3.5 以支援 .NET 3.5 語法。<#@ output extension=".txt" #>:輸出副檔名與編碼。<#@ LanguageSm processor="..." requires="..." #>:宣告指令處理器與要載入的模型檔。<# ... #>:標準控制區塊,放 C#/VB 控制陳述式。<#+ ... #>:類別特性區塊,放可重用的方法、屬性、巢狀類別。<#= ... #>:運算式區塊,計算值並輸出。T4 類似 ASPX,會編譯成衍生自 ModelingTextTransformation 的類別,TransformText() 透過 Write() 輸出內容,Initialize() 載入模型 (透過 SerializationHelper.LoadModel)。
根據模型圖,欲生成程式碼結構:
public enum OrderStateEnum { Draft, NewOrder, Cancelled, Confirmed }
public partial class Order
{
public OrderStateEnum OrderState { get; set; }
public Order() {}
public void Save(Order order) { /* 存檔邏輯 */ }
// 每個 Transition 產生一個方法
protected void SaveOrder(Order order) {
if (order.OrderState == OrderStateEnum.Draft)
order.OrderState = OrderStateEnum.NewOrder;
Save(order);
}
protected void CancelOrder(Order order) { ... }
protected void ConfirmOrder(Order order) { ... }
}
OrderState。<#+
System.Collections.Generic.IEnumerable<Transition> GetAllTransitions() {
foreach (State s in StateMachine.States)
foreach (Transition t in Transition.GetLinksToSuccessors(s))
yield return t;
}
#>
/// <summary>
/// 訂單狀態
/// </summary>
public enum OrderStateEnum
{
<#
PushIndent(" ");
foreach (State state in StateMachine.States)
WriteLine(" {0},", state.Name);
PopIndent();
#>
}
/// <summary>
/// 訂單生成
/// </summary>
public partial class Order
{
public OrderStateEnum OrderState { get; set; }
public Order() {}
public void Save(Order order){ /* to save order */ }
<#
foreach (Transition transition in GetAllTransitions()) {
#>
protected void <#= transition.Event #>(Order order)
{
if (order.OrderState == OrderStateEnum.<#= transition.Predecessor.Name #>)
order.OrderState = OrderStateEnum.<#= transition.Successor.Name #>;
Save(order);
}
<#
}
#>
}
執行「轉換所有範本」或右鍵 T4 檔案「執行自訂工具」,產生完整程式碼:
/// <summary>
/// 訂單狀態
/// </summary>
public enum OrderStateEnum
{
Draft,
NewOrder,
Cancelled,
Confirmed,
}
/// <summary>
/// 訂單生成
/// </summary>
public partial class Order
{
public OrderStateEnum OrderState { get; set; }
public Order() {}
public void Save(Order order){ /* to save order */ }
protected void SaveOrder(Order order)
{
if (order.OrderState == OrderStateEnum.Draft)
order.OrderState = OrderStateEnum.NewOrder;
Save(order);
}
protected void CancelOrder(Order order)
{
if (order.OrderState == OrderStateEnum.NewOrder)
order.OrderState = OrderStateEnum.Cancelled;
Save(order);
}
protected void ConfirmOrder(Order order)
{
if (order.OrderState == OrderStateEnum.NewOrder)
order.OrderState = OrderStateEnum.Confirmed;
Save(order);
}
}
T4 無法在生成檔中保留手寫自訂邏輯 (每次重新生成會覆蓋)。實務上採用 partial class 分檔策略:
如此模型修改後重新生成,不會覆蓋手寫邏輯。