• 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

  • 相关阅读:
    走读OpenSSL代码从一张奇怪的证书说起(二)
    从数学到密码学(十八)
    从数学到密码学(十七)
    走读OpenSSL代码从一张奇怪的证书说起(一)
    从数学到密码学(十六)
    从数学到密码学(十五)
    从数学到密码学(十三)
    从数学到密码学(十九)
    从数学到密码学(十四)
    关于Terracotta DSO 安装
  • 原文地址:https://www.cnblogs.com/liweis/p/6703314.html
Copyright © 2020-2023  润新知