表达式求值是一个很有意思的技术话题,国内外讨论这个话题的技术人员很多,也有非常多的实现方案。倒不是说这个问题很难解决,只是说它提供了很好的话题,让各路高手使用自己的手段来解决问题,百家争鸣,各展所长。该话题也提供了一个非常好的想像空间让大家一起讨论技术讨论方案,也是一个数据结构教程中的经典教育案例。
一般可以使用堆栈,表达式树(.Net)之类的方法解决,但如果要实现比较复杂的表达式求值,如数据方法求值,字符串,是否求值,方法计算等等,那就不是教学案例了,应该是一个编译器的问题了。即是编写一个编译器来计算表达式的值。这似乎就没那么简单,也不是一般技术活了。
复杂的表达式求值怎样解决
幸好,.net已经有了动态编译的接口,即在运行时,直接将一堆字符编译为机器码并可以运行。这为复杂的表达式求值提供了一个手段。.net提供了System.CodeDom命名空间,该空间下有多个编译相关的类,使用这些类就可以实现动态的编译和执行。不过这个编译的过程与VS2008等,事实上是一样的,如果代码简单编译就是快,如果代码复杂就很慢,生成的内容也很慢。这是因为.net是预编译机制,编译好之后才进行调用或计算,如果要马上编译马上计算,那运行的效率就不会高了。
运行效率不高,如果在大型高并发运算中,是一个不可以忽视的问题,但如果只是小量计算,或者使用的是客户端资源进行计算,不影响服务器的性能的话,动态编译也是个非常可靠的方法。您可以在代码中实现任何的功能,所有.net的api,方法和类,你都可以使用,而且编译解释引擎非常的可靠,那着实是不可多得的好东西。如果你要动态编译的内容是固定的,而不是每一次都会发生变化的表达式,那就更加好了,编译出来的类和方法都可以缓存起来,下一次就可以直接使用了,效率与平常写代码是一样的。
使用.net动态编译器来解释计算公式,不失为一种可行,稳定,可靠的表达式求值解决方案,不过如果要直接使用.Net动态编译器,还要生成一个类,写一部分代码,如using,class等等,还要有一定的扩展性,那就不一定个个人都想搞那么多了。使用CKRule可以大大简化这个过程。
序号 |
需求特点 |
CKRule使用方法 |
1 |
不需要固定的对象,方法,只要解释表达式 |
新建一个规则包*.ckp,直接传入表达式参数。 |
2 |
要有固定对象,内置方法 |
在新建的规则包中,增加这些方法,并直接调用。 |
在您的程序中实现表达式求值
程序运行截图:
代码实现:
if (string.IsNullOrEmpty(txtWord.Text.Trim()))
{
MessageBox.Show("脚本内容不能为空!");
}
try
{
var _result = new RuleFacade().TestPool<object>(FrmRulePoolSet.RuleInstName, txtWord.Text);
txtResult.Text = "结果是:" + _result;
}
catch (Exception exp)
{
MessageBox.Show(exp.Message);
}
只使用了一个最简单的接口,RuleFacade类的TestPool方法。并传入规则包的名称和表达式内容,您就可以使用非常丰富的表达式求值。
但之前已经提到,.net动态编译的机制,注定这种动态求值的方案并不是很适应于大型的高并发计算中,不过如果是使用客户端的桌面资源或对并发要求不高的情况下,还是很好用的。
源代码下载 : http://www.ckrule.com/cn/demo.html
表达式求值的实现