背景
做流程引擎最終避免不了一個問題:如何動態解析路由規則?
幾乎所有的審批流程都要求支持條件路由,比如:請假天數大於xx天時某個領導審批,否則其它人審批。常見的解決方法有:一、動態編譯;二、解釋執行。這篇文章就講解如何使用Javascript引擎解釋執行。
思路
靜態語言集成動態語言解釋器這種模式,在業界已經有很多慣例,如:很多C++開發者都用Lua在運行時修改配置。因為我對Javascript比較熟悉,所以准備搜索一下Javascript的解釋器。在NuGet中用Javascript關鍵字進行搜索,搜索到了第2頁就找到了一個解釋器,安裝一下,准備嘗試吧。
實現
代碼下載:http://yunpan.cn/Q5jj9D2GKBZGh。
幾乎我接觸的所有解釋器引擎提供的API都很相似,所以這里我直接貼代碼了。
CondiationCalculator.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 using Jurassic; 8 9 namespace DynamicExpressionStudy 10 { 11 public static class CondiationCalculator 12 { 13 public static bool IsSatisfied(object entity, string expression) 14 { 15 var engine = new ScriptEngine(); 16 17 if (entity != null) 18 { 19 foreach (var property in entity.GetType().GetProperties()) 20 { 21 engine.SetGlobalValue(property.Name, property.GetValue(entity)); 22 } 23 } 24 25 return engine.Evaluate<bool>(expression); 26 } 27 28 public static bool IsSatisfied(Dictionary<string, object> variables, string expression) 29 { 30 var engine = new ScriptEngine(); 31 32 if (variables != null) 33 { 34 foreach (var variable in variables) 35 { 36 engine.SetGlobalValue(variable.Key, variable.Value); 37 } 38 } 39 40 return engine.Evaluate<bool>(expression); 41 } 42 } 43 }
Program.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace DynamicExpressionStudy 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 { 14 var leave = new Leave 15 { 16 LeaveDays = 5, 17 LeaveType = "病假" 18 }; 19 20 var result = CondiationCalculator.IsSatisfied(leave, "LeaveDays>=5 && LeaveType=='病假'"); 21 22 Console.WriteLine(result); 23 } 24 25 { 26 var leave = new Dictionary<string, object> 27 { 28 { "LeaveDays", 5 }, 29 { "LeaveType", "病假" } 30 }; 31 32 var result = CondiationCalculator.IsSatisfied(leave, "LeaveDays>=5 && LeaveType=='病假'"); 33 34 Console.WriteLine(result); 35 } 36 } 37 } 38 39 public class Leave 40 { 41 public int LeaveDays { get; set; } 42 43 public string LeaveType { get; set; } 44 } 45 }
執行結果
備注
有朋友會說這種方式是不是速度會比較慢,確實是慢,不過考慮到一次只判斷一個單據,還是可以接受的。
如果要求接近C#的速度,可以采用動態編譯+緩存動態程序集的方式,我就用過一次。