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类)的组合。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /// <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(); } |
调用:
1 | SimpleEval( this .textBox1.Text.Trim() |
结果如下:
4.第二种情况,其中包含了一些变量(这种情况更多),需要将自己的变量写成一个类,然后注册这个类。
类
1 2 3 4 5 | public class Result { public double Death { get ; set ; } public double Injury { get ; set ; } } |
方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /// <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(); } |
调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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://www.cnblogs.com/liweis/
签名:成熟是一种明亮而不刺眼的光辉。

【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步