您的位置:首页 > 编程语言 > C#

在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文件中,如下

<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#要强
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐