在C#中解决动态计算表达式的问题(如字符串"Sin(1)+Cos(2)",执行并得出结果)
2014-02-20 16:14
1006 查看
前一阵公司老总要求我去重构一个同事的程序,里面有各种计算公式,如下图
这个公式的算法是这样
0.058419 + 0.084612 * (log10(第二个文本框的值 / 第一个文本框的值)) + 0.3464 * 第三个文本框的值 + 0.00387 * 第四个文本框的值
另一个公式如下图
公式是这样
0.135 + 0.165 * log10(第一个文本框的值/第二个文本框的值)
这两个公式用的是同一窗体,只是加载窗体的时候使用不同的公式而已,所以界面显示的文本框数量,和一些说明文字不一样.
每个公式需要的参数个数不一同,公式算法不一样
我脑海里第一个闪现的做法就是把这些信息整合进一个XML里面进行配置,把计算的公式放进XML里面,呵呵,但是这样仍然解决不了我的问题
现在的公式成了字符串了,而不是程序里面的变量.
由此我想到几种解决方案,它们都属于动态编译,我找到一本英文资料,专门讲C#的元编程<<Manning Metaprogramming in NET 2013>>
这本书提到几种动态编译的方法
1.CodeDom
2.Refection.Emit
3.Lambda表达式树
4.DLR
4个我都看了一下,做了以下总结跟实践
方法1非常好,可以动态编译C#的代码,比如在一个文件框里写MessageBox.Show(......)然后读取文本框里的代码执行,就可以弹出一个文本框,如下图
由此我找到两个来自CodeProject的程序
http://www.codeproject.com/Articles/11939/Evaluate-C-Code-Eval-Function
http://www.codeproject.com/Articles/18004/Net-Expression-Evaluator-using-DynamicMethod
这两个例子都非常好,尤其是第一个例子,演示了怎么执行一段字符串写的代码,以及外部的代码怎么跟字符串写的代码交互,但是要完成我的需要,要写的代码不少!
方法2是操作IL中间语言,我看了一下它的生成代码方式,有一定的灵活度,但要达到我这个程序的要求是太难,太烦,太麻烦!
方法3其生成代码的过程跟方法2比较像,但要轻量级一些,没那么繁琐,它主要是为了动态的生成一个Lambda表达式,但跟方法2一样,不太方便
方法4DLR与动态语言交互,目前.net已经很好的支持了两种脚本语言,Python和Ruby!看了一下Python的语法,感觉比较"轻便"!于是我把公式的计算翻译成Python代码并放入XML文件中,如下
/article/2580834.html
关于IronPython的资料还有一篇写的比较好:
C# 4.0 动态调用 IronPython
http://blog.csdn.net/goldworm2012/article/details/7621632
这个工作做完以后,我感觉方法1还是不错的,但是跟方法4相比,它稍微"重"了一点,但是在执行其它任务时,它是最好的(比如执行一段由字符串写的代码),方法4用来做动态解析计算的时候最合适,代码量少,清晰,并且Python在做科学计算方面比C#要强
这个公式的算法是这样
0.058419 + 0.084612 * (log10(第二个文本框的值 / 第一个文本框的值)) + 0.3464 * 第三个文本框的值 + 0.00387 * 第四个文本框的值
另一个公式如下图
公式是这样
0.135 + 0.165 * log10(第一个文本框的值/第二个文本框的值)
这两个公式用的是同一窗体,只是加载窗体的时候使用不同的公式而已,所以界面显示的文本框数量,和一些说明文字不一样.
每个公式需要的参数个数不一同,公式算法不一样
我脑海里第一个闪现的做法就是把这些信息整合进一个XML里面进行配置,把计算的公式放进XML里面,呵呵,但是这样仍然解决不了我的问题
现在的公式成了字符串了,而不是程序里面的变量.
由此我想到几种解决方案,它们都属于动态编译,我找到一本英文资料,专门讲C#的元编程<<Manning Metaprogramming in NET 2013>>
这本书提到几种动态编译的方法
1.CodeDom
2.Refection.Emit
3.Lambda表达式树
4.DLR
4个我都看了一下,做了以下总结跟实践
方法1非常好,可以动态编译C#的代码,比如在一个文件框里写MessageBox.Show(......)然后读取文本框里的代码执行,就可以弹出一个文本框,如下图
由此我找到两个来自CodeProject的程序
http://www.codeproject.com/Articles/11939/Evaluate-C-Code-Eval-Function
http://www.codeproject.com/Articles/18004/Net-Expression-Evaluator-using-DynamicMethod
这两个例子都非常好,尤其是第一个例子,演示了怎么执行一段字符串写的代码,以及外部的代码怎么跟字符串写的代码交互,但是要完成我的需要,要写的代码不少!
方法2是操作IL中间语言,我看了一下它的生成代码方式,有一定的灵活度,但要达到我这个程序的要求是太难,太烦,太麻烦!
方法3其生成代码的过程跟方法2比较像,但要轻量级一些,没那么繁琐,它主要是为了动态的生成一个Lambda表达式,但跟方法2一样,不太方便
方法4DLR与动态语言交互,目前.net已经很好的支持了两种脚本语言,Python和Ruby!看了一下Python的语法,感觉比较"轻便"!于是我把公式的计算翻译成Python代码并放入XML文件中,如下
<FormulaInfo MethodSmartPart = "EmpiricalCyq" FormulaName="陈元千相关经验公式" ParameterNameGroup = "地层原油粘度μo(mPa.s)|平均空气渗透率K(mD)|有效孔隙度φ(f)|井网密度S(口/km²)" ParameterRange = "0.5-154.0|4.8-8900.0|0.15-0.33|3.1-28.3" ValidParameter = "0.5-154.0|4.8-8900.0|0.15-0.33|3.1-28.3" Image = "陈元千相关经验公式" Code="def cal(): return 0.058419 + 0.084612 * (log10(float(ArrayCan[1].Text) / float(ArrayCan[0].Text))) + 0.3464 * float(ArrayCan[2].Text) + 0.00387 * float(ArrayCan[3].Text)" />具体做法,我在我的另一篇文章里面有
/article/2580834.html
关于IronPython的资料还有一篇写的比较好:
C# 4.0 动态调用 IronPython
http://blog.csdn.net/goldworm2012/article/details/7621632
这个工作做完以后,我感觉方法1还是不错的,但是跟方法4相比,它稍微"重"了一点,但是在执行其它任务时,它是最好的(比如执行一段由字符串写的代码),方法4用来做动态解析计算的时候最合适,代码量少,清晰,并且Python在做科学计算方面比C#要强
相关文章推荐
- 用于执行(计算) "字符串表达式" 的 T-SQL 存储过程
- 代码详解の使用CountDownLatch解决面试问题:T1和T2线程执行计算,T3线程计算结果的统计
- C#中另类自定义公式计算 字符串转换为计算公式,并得出计算结果
- 关于PLSQL Developer报"动态执行表不可访问,本会话的自动统计被禁止"错的解决方法 .
- Enterprise Library- Data Block使用oracle存储过程,字符串参数传入值为""时出现问题的解决
- 解决"当前命令发生了严重错误。应放弃任何可能产生的结果。"的问题
- 解决从服务器获取的数组是 __NSCFConstantString以及&quot;&quot;没有空格字符串的问题
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java)
- 在"Select top 2 * from news order by count"进行筛选时,如果count值有重复时,则筛选结果将不是2条记录,这个问题该怎么解决?
- PL\SQL 打开时出现"动态执行表不可访问,本会话的自动统计被禁止"错误解决
- TNS-01190: 用户无权执行所请求的监听程序命令"问题解决
- C#将字符串转换成运算表达式并得到计算结果
- c#中实现类似js的Eval|.NET中执行Javascript(表达式是字符串的计算)
- MYSQL 执行Insert语句throws "The table 'xxx' is full" 的问题分析及解决办法
- 数据结构之应用 "栈(Stack)" 实现: 解析算术表达式及计算求值 (C#/Java) (转载)
- 解决C#中一个"异步方法却同步执行"的问题
- 总结Asp.net中Page加载PostData的具体过程 进而解决"获取动态创建的控件的PostData数据"问题
- 解决C#后台返回json数据双引号转义为"问题
- (C#)计算字符串排列组合数 如"abcd"组合数为24 "aabb"组合数为6
- 【.Net码农】Asp.Net异常:"由于代码已经过优化或者本机框架位于调用堆栈之上,无法计算表达式的值"的解决方法