C# 動態解析表達式


需求

我們很難捉摸用戶的思維,即使使用非常正式的文檔規范某些數據的定義、結果的標准等,也不能抵擋住用戶不斷變化的需求,但他們有個萬變不離的東西——你做這個東西要是萬能的,即輸入參數類型、個數等發生改變,也得生成出正確的結果。

在編程計算中,很多時候涉及一些公式,用戶要求不但能夠調整系數、還要能夠調整理公式的結構。例如,將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函數:

http://csharpeval.codeplex.com/discussions/585878


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM