需求
我们很难捉摸用户的思维,即使使用非常正式的文档规范某些数据的定义、结果的标准等,也不能抵挡住用户不断变化的需求,但他们有个万变不离的东西——你做这个东西要是万能的,即输入参数类型、个数等发生改变,也得生成出正确的结果。
在编程计算中,很多时候涉及一些公式,用户要求不但能够调整系数、还要能够调整理公式的结构。例如,将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://csharpeval.codeplex.com/discussions/585878
本文转自我也是个傻瓜51CTO博客,原文链接: http://www.cnblogs.com/liweis/p/6703314.html,如需转载请自行联系原作者