背景
在上篇文章中我介紹了如何用動態語言解釋器執行路由規則,有很多朋友都給出了他們的選項,如下:
-
- 集成解釋器(Iron、Javascript等)。
- 動態編譯。
- 解析為Lamda表達式。
- 模板引擎。
因為我覺得動態編譯很有意思,結合T4可能會更舒服,這篇文章就用這個思路重新實現一下如何解析路由規則。
思路
T4 + 動態編譯 = 無限可能
如何使用動態編譯解析這條規則(“LeaveDays>=5 && LeaveType=='病假'”)呢?思路有很多種,我立馬想到的的有兩種,將Leave的屬性解析為某個方法的本地變量或方法所有類型的成員變量,下面就是動態編譯后的方法:
1 public bool IsSatisfied(Leave entity) 2 { 3 var LeaveDays = entity.LeaveDays; 4 var LeaveType = entity.LeaveType; 5 return LeaveDays>=5 && LeaveType=="病假"; 6 }
實現(代碼下載)
CSharpDynamicSpecification.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 Microsoft.CSharp; 8 using System.CodeDom.Compiler; 9 10 namespace DynamicExpressionStudy 11 { 12 public sealed class CSharpDynamicSpecification<T> : IDynamicSpecification<T> 13 { 14 private string _expression; 15 16 public CSharpDynamicSpecification(string expression) 17 { 18 _expression = expression; 19 } 20 21 public bool IsSatisfied(T entity) 22 { 23 var dynamicInstance = this.CompileAndCreateInstance(); 24 25 var result = dynamicInstance 26 .GetType() 27 .GetMethod("IsSatisfied") 28 .Invoke(dynamicInstance, new object[] { entity }); 29 30 return (bool)result; 31 } 32 33 private object CompileAndCreateInstance() 34 { 35 CodeDomProvider provider = new Microsoft.CSharp.CSharpCodeProvider(); 36 37 CompilerParameters cp = new CompilerParameters(); 38 cp.GenerateExecutable = false; 39 cp.GenerateInMemory = true; 40 cp.TreatWarningsAsErrors = false; 41 cp.ReferencedAssemblies.Add(Environment.CurrentDirectory + "\\DynamicExpressionStudy.exe"); 42 43 var templator = new DynamicSpecificationClassTemplate(typeof(T), _expression); 44 var sourceCode = templator.TransformText(); 45 46 CompilerResults cr = provider.CompileAssemblyFromSource(cp, sourceCode); 47 48 return Activator.CreateInstance(cr.CompiledAssembly.GetType("DynamicExpressionStudy." + templator.TempClassName)); 49 } 50 } 51 }
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 var leave = new Leave 14 { 15 LeaveDays = 5, 16 LeaveType = "病假" 17 }; 18 19 var specification = new CSharpDynamicSpecification<Leave>("LeaveDays>=5 && LeaveType==\"病假\""); 20 21 var result = specification.IsSatisfied(leave); 22 23 Console.WriteLine(result); 24 } 25 } 26 27 public class Leave 28 { 29 public int LeaveDays { get; set; } 30 31 public string LeaveType { get; set; } 32 } 33 }
運行結果為:true。
備注
這些解析路由規則的思路,可以用在其他任何需要動態計算的場合,如:薪酬公式、考核公式、考勤公式等。