需求
我們很難捉摸用戶的思維,即使使用非常正式的文檔規范某些數據的定義、結果的標准等,也不能抵擋住用戶不斷變化的需求,但他們有個萬變不離的東西——你做這個東西要是萬能的,即輸入參數類型、個數等發生改變,也得生成出正確的結果。
在編程計算中,很多時候涉及一些公式,用戶要求不但能夠調整系數、還要能夠調整理公式的結構。例如,將2+3-5調整理成2+3*5。我之前使用的解決方案是寫一個類,換公式了,就繼承它,寫一個子類,代碼中用反射去調用這個子類,可以解決問題。但是有些麻煩。
解決方案
現決定,用動態來解析公式的方法來解決這個問題。由於時間比較緊張,找到了一個開源的類庫ExpressionEvaluator,沒有深入研究,不過已經解決了我們的問題。
官網:http://csharpeval.codeplex.com/
使用示例
1.在官網下載ExpressionEvaluator. dll(2.0.4版),在網上搜索antlr3.runtime.dll(3.5.0.2版)
2.項目中引用這兩個dll;
3.第一種情況,不需要變量,直接是常規的數字、符號、系統函數(Math類)的組合。
/// <summary> /// 簡單數值計算 /// </summary> /// <param name="str">純表達式</param> /// <returns>返回值</returns> public static string SimpleEval(string str) { var types = new TypeRegistry(); types.RegisterDefaultTypes(); var expression = new CompiledExpression(str) { TypeRegistry = types }; var result = expression.Eval(); Console.WriteLine("簡單數值計算: {0}", result); return result.ToString(); }
調用:
SimpleEval(this.textBox1.Text.Trim()
結果如下:
4.第二種情況,其中包含了一些變量(這種情況更多),需要將自己的變量寫成一個類,然后注冊這個類。
類
public class Result { public double Death { get; set; } public double Injury { get; set; } }
方法:
/// <summary> /// 變量字段的計算 /// </summary> /// <param name="str"></param> /// <param name="type"></param> /// <returns></returns> public static string FieldEval(string str,Object type) { //注冊 var reg = new TypeRegistry(); reg.RegisterSymbol("Result", type); //如果要使用Math函數,還就注冊這個 //reg.RegisterDefaultTypes(); //編譯 var p = new CompiledExpression(str) { TypeRegistry = reg }; p.Compile(); //計算 Console.WriteLine("變量字段計算: {0}", p.Eval()); return p.Eval().ToString(); }
調用:
string[] strFields = new string[] { "Death","Injury"}; string exp = this.textBox2.Text.Trim(); for (int i = 0; i < strFields.Length;i++ ) { if (exp.Contains(strFields[i])) { exp= exp.Replace(strFields[i], "Result." + strFields[i]); } } Result re = new Result() { Death = Convert.ToDouble(this.txtDeath.Text.Trim() + ""), Injury = Convert.ToDouble(this.txtInjury.Text.Trim() + "") }; ExpEvaluator.FieldEval(exp,re)
結果:
當然,還有其他內容需要研究、學習!
參考
Github地址:
https://github.com/RupertAvery/csharpeval
調用系統的Math函數: