當系統需要處理特定領域的語法規則(如數學表達式、規則引擎、查詢語言、配置腳本)時,硬編碼解析邏輯會導致系統僵化、難以擴展。解釋器模式提供一種建構「語言解釋器」的架構:定義文法表示,並實作解釋器將句子轉換為可執行操作。本文透過中文語法「{數據庫}[信息](獲取)」動態解析為 C# 程式碼 SqlMessage.Get() 並透過反射執行,完整展示解釋器模式的核心機制與實戰應用。
Context 類別,攜帶輸入字串 Input 與解釋輸出 Output,作為解釋過程的狀態容器。AbstractExpression,定義 Interpret(Context) 解釋操作,內含字典查表邏輯與抽象方法 GetWord()、GetDictionary() 留待子類別實作。DatabaseExpression、ObjectExpression、MethodExpression,分別解析大括號、中括號、小括號內的關鍵字,並對應至 C# 程式碼片段。Interpret(),最後透過反射動態執行生成的程式碼。
本範例定義簡單中文文法:
{數據庫} → 對應類別名稱前綴(Sql)[信息] → 對應類別名稱主體(Message)(獲取) → 對應方法名稱(.Get()){數據庫}[信息](獲取) → SqlMessage.Get()Context 類別攜帶輸入與輸出:
public class Context
{
public string Input { get; set; }
public string Output { get; set; }
public Context(string input) { this.Input = input; }
}
public abstract class AbstractExpression
{
public void Interpret(Context context)
{
if (String.IsNullOrEmpty(context.Input)) return;
context.Output += GetCSharp(context.Input);
}
private string GetCSharp(string source)
{
string word = GetWord(source); // 子類別實作:提取關鍵字
GetDictionary().TryGetValue(word, out string csharp); // 子類別實作:字典查表
return csharp;
}
protected abstract string GetWord(string source); // 正則提取邏輯
protected abstract Dictionary<string, string> GetDictionary(); // 映射字典
}
模板方法模式應用:Interpret() 定義解釋骨架,GetWord()、GetDictionary() 為可變步驟延遲至子類別。
DatabaseExpression:解析 {...} → 類別前綴
public class DatabaseExpression : AbstractExpression
{
protected override string GetWord(string source)
{
var mc = Regex.Matches(source, @"\{(.*)\}");
return mc[0].Groups[1].Value; // 取 "數據庫"
}
protected override Dictionary<string, string> GetDictionary()
=> new Dictionary<string, string> { { "數據庫", "Sql" } };
}
ObjectExpression:解析 [...] → 類別主體
public class ObjectExpression : AbstractExpression
{
protected override string GetWord(string source)
=> Regex.Match(source, @"\[(.*)\]").Groups[1].Value; // 取 "信息"
protected override Dictionary<string, string> GetDictionary()
=> new Dictionary<string, string> { { "信息", "Message" } };
}
MethodExpression:解析 (...) → 方法
public class MethodExpression : AbstractExpression
{
protected override string GetWord(string source)
=> Regex.Match(source, @"\((.*)\)").Groups[1].Value; // 取 "獲取"
protected override Dictionary<string, string> GetDictionary()
=> new Dictionary<string, string> { { "獲取", ".Get()" } };
}
string chinese = "{數據庫}[信息](獲取)";
Context context = new Context(chinese);
var expressions = new List<AbstractExpression>
{
new DatabaseExpression(),
new ObjectExpression(),
new MethodExpression()
};
foreach (var exp in expressions)
exp.Interpret(context); // 依序解釋,輸出累積至 context.Output
// context.Output = "SqlMessage.Get()"
// 反射動態執行
var assembly = Assembly.Load("Pattern.Interpreter");
var typeName = context.Output.Split('.')[0]; // "SqlMessage"
var methodName = context.Output.Split('.')[1].Replace("()", ""); // "Get"
var method = assembly.GetType("Pattern.Interpreter." + typeName).GetMethod(methodName);
var result = method.Invoke(null, null); // 靜態方法無需實例
var messages = (List<MessageModel>)result;
Response.Write("中文語法:" + chinese);
Response.Write("解釋後的C#代碼:" + context.Output);
Response.Write("執行結果:" + messages[0].Message);
中文語法:{數據庫}[信息](獲取)
解釋後的C#代碼:SqlMessage.Get()
執行結果:SQL方式獲取Message 2007-5-1 8:48:07
完美驗證:中文語法 → 解釋器鏈 → C# 程式碼字串 → 反射執行 → 實際業務結果。
本範例僅有終結符(葉子節點)。實際語言常需非終結符(組合節點),如:
AndExpression、OrExpression:邏輯組合SequenceExpression:順序執行多個子表達式RepeatExpression:循環執行非終結符持有子表達式集合,Interpret() 遞迴呼叫子表達式,構建抽象語法樹(AST)。
手寫解釋器適用於簡單文法。複雜語言建議使用:
System.Linq.Expressions 建構 Lambda 運算式樹並編譯為委派,執行速度接近原生程式碼。解釋器模式為「語言處理」提供了標準化架構:Context 攜帶狀態、AbstractExpression 定義解釋骨架、TerminalExpression 實作終結符映射、NonTerminalExpression 組合複雜結構。本範例以中文語法動態生成 C# 程式碼並反射執行為例,展示了從文法定義、正則提取、字典映射、鏈式解釋到動態執行的完整鏈路。雖然手寫解釋器適用於簡單 DSL,但掌握其核心機制(AST、遞迴下降、Context 傳遞)能讓你在需要「可配置、可擴展、動態執行」的業務規則系統中,做出正確的架構選型:簡單用手寫解釋器、複雜上 ANTLR/Roslyn、效能敏感用運算式樹。這正是解釋器模式在現代軟體工程中的實戰價值所在。