利用System.Linq.Expressions实现四则运算计算器(三)

利用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中表达式的应用了吧?

posted on 2007-08-30 22:50  sdxd.bgl  阅读(1493)  评论(0编辑  收藏  举报

导航