需求
我們很難捉摸用戶的思維,即使使用非常正式的文檔規范某些數據的定義、結果的標准等,也不能抵擋住用戶不斷變化的需求,但他們有個萬變不離的東西——你做這個東西要是萬能的,即輸入參數類型、個數等發生改變,也得生成出正確的結果。
在編程計算中,很多時候涉及一些公式,用戶要求不但能夠調整系數、還要能夠調整理公式的結構。例如,將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函數:
