






















利用System.Linq.Expressions实现四则运算计算器(三)
将表达式树转换成.NET定义的表达式树
请大家留意上次提供的类图:

抽象类BWExpression提供了一个抽象方法GetExpression,这个方法就是用于获取表达式类的。
对于常量表达式BWConstantExpressionNode节点,GetExpression只需把数字作为常量表达式返回:
///<summary>
///生成表达式
///</summary>
///<returns>表达式</returns>
public override Expression GetExpression()
{
return Expression.Constant(this.Operand, typeof(double));
}
对于BWExpressionNodeCollection节点,GetExpression需要对其表达式子节点针对运算符优先级进行组合。
///<summary>
///生成表达式
///</summary>
///<returns>表达式</returns>
public override Expression GetExpression()
{
// 1 + 5 * 9 - ( 1 + 2 ) * 3 / 4 + 6 * ( -2 )
// 将加、减放入队列中,乘、除计算后也放入队列中
List<ExpressionWriper> expressionList = new List<ExpressionWriper>();
expressionList.Add(new ExpressionWriper(this.expressionNodeList[0].GetExpression(), this.expressionNodeList[0].ExpressionNodeType));
for (int i = 1; i < this.expressionNodeList.Count; i++)
{
BWExpressionNode currentNode = this.expressionNodeList[i];
switch (currentNode.ExpressionNodeType)
{
case BWExpressionNodeType.Addition:
case BWExpressionNodeType.Subtration:
expressionList.Add(new ExpressionWriper(currentNode.GetExpression(), currentNode.ExpressionNodeType));
break;
case BWExpressionNodeType.Multiplication:
{
ExpressionWriper preNode = expressionList[expressionList.Count - 1];
expressionList[expressionList.Count - 1] = new ExpressionWriper(Expression.Multiply(preNode.Expression, currentNode.GetExpression()), preNode.ExpressionNodeType);
break;
}
case BWExpressionNodeType.Division:
{
ExpressionWriper preNode = expressionList[expressionList.Count - 1];
expressionList[expressionList.Count - 1] = new ExpressionWriper(Expression.Divide(preNode.Expression, currentNode.GetExpression()), preNode.ExpressionNodeType);
break;
}
}
}
Expression expression = null;
// 对队列中的加、减进行计算
for (int i = 0; i < expressionList.Count; i++)
{
ExpressionWriper wriper = expressionList[i];
switch (wriper.ExpressionNodeType)
{
case BWExpressionNodeType.Start:
expression = wriper.Expression;
break;
case BWExpressionNodeType.Addition:
expression = Expression.Add(expression, wriper.Expression);
break;
case BWExpressionNodeType.Subtration:
expression = Expression.Subtract(expression, wriper.Expression);
break;
case BWExpressionNodeType.Multiplication:
expression = Expression.Multiply(expression, wriper.Expression);
break;
case BWExpressionNodeType.Division:
expression = Expression.Divide(expression, wriper.Expression);
break;
}
}
return expression;
}
在这个方法中,我引入一个辅助类ExpressionWriper,用于保存临时表达式和其前面的符号。
private class ExpressionWriper
{
public BWExpressionNodeType ExpressionNodeType { get; set; }
public Expression Expression { get; set; }
public ExpressionWriper(Expression expression, BWExpressionNodeType type)
{
this.Expression = expression;
this.ExpressionNodeType = type;
}
}
这个GetExpression方法中,使用一个列表来临时存储加减表达式。由于乘法和除法需要优先计算,在方法中,先是把第一个表达式放入队列,再判断第二个表达式的符号,如果是加号或者减号,则直接把第二个表达式放入队列,如果遇到的是乘号或除号,则把队列的最后一个拿出来与当前表达式进行计算,结果放回队列的最后一个。这样,就保持了队列中只有加减表达式,没有乘除,因为乘法和除法都计算过了。看下面的流程图。

这个方法最后得到一个包含所有节点和子节点的表达式,返回给调用者。
为了方便使用,我写了一个静态方法,从传入字符串到得到计算结果,一次完成!
public class BWExpression
{
Func<double> func;
public Func<double> Func
{
get { return func; }
set { func = value; }
}
public void CreateFunc(string input)
{
// 1 + 5 * 9 - ( 1 + 2 ) * 3 / 4 + 6 * ( -2 )
BWExpressionNodeCollection nodes = new BWExpressionNodeCollection(input, BWExpressionNodeType.Start);
Expression expression = nodes.GetExpression();
Expression<Func<double>> lamdbaExpression = Expression.Lambda<Func<double>>(expression);
func = lamdbaExpression.Compile();
}
public static double Calculate(string expressionString)
{
BWExpression expression = new BWExpression();
expression.CreateFunc(expressionString);
return expression.Func();
}
}
CreateFunc(string input)方法在《初识System.Linq.Expressions》中提到过,大家可以连接过去看看。
最后建一个窗体:
按钮的事件处理如下:
private void btnCalc_Click(object sender, EventArgs e)
{
try
{
txtOutput.Text = BWExpression.Calculate(txtInput.Text).ToString();
}
catch
{
MessageBox.Show("表达式错误!");
}
}
好啦!一个完整的四则运算的简单计算器就做好啦!大家大概了解System.Linq.Expressions中表达式的应用了吧?
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。