惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - sdxd.bgl

将SQL Server中的数据显示到SharePoint中 - sdxd.bgl 拓展训练总结 在PowerShell中,如何获取SharePoint的默认数据库服务器 在SharePoint页面中如何显示来自其他网站的List 恢复导出XSLT List View WebPart - sdxd.bgl 实战部署FAST Search Server 2010 for SharePoint Sharepoint开发中代码运行权限级别 在InfoPath中如何获取当前用户的信息(Profile) 晒晒我的家乡 关于模式的思考 小心委托 利用System.Linq.Expressions实现四则运算计算器(二) 利用System.Linq.Expressions实现四则运算计算器(一) 初识System.Linq.Expressions 请拆招:将两个已排序集合分解成两个独立部分的集合和一个共有部分的集合? 如何实现Windows服务 用javascript实现下拉列表的自动筛选功能 - sdxd.bgl - 博客园 我的生活 电脑是个神奇的东西!
利用System.Linq.Expressions实现四则运算计算器(三)
sdxd.bgl · 2007-08-30 · via 博客园 - sdxd.bgl

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