设为首页 加入收藏

TOP

Lambda表达式和表达式树
2015-03-04 22:51:07 来源: 作者: 【 】 浏览:40
Tags:Lambda 表达式

在C# 2.0中,通过方法组转换和匿名方法,使委托的实现得到了极大的简化。但是,匿名方法仍然有些臃肿,而且当代码中充满了匿名方法的时候,可读性可能就会受到影响。C# 3.0中出现的Lambda表达式在不牺牲可读性的前提下,进一步简化了委托。


LINQ的基本功能就是创建操作管道,以及这些操作需要的任何状态。这些操作表示了各种关于数据的逻辑,例如数据筛选,数据排序等等。通常这些操作都是用委托来表示。Lambda表达式是对LINQ数据操作的一种符合语言习惯的表示方式。


Lambda表达式不仅可以用来创建委托实例,C#编译器也能够将他们转换成表达式树。


下面我们就先看看Lambda表达式。


Lambda表达式可以看作是C# 2.0的匿名方法的进一步演变,所以匿名方法能做的几乎一切事情都可以用Lambda表达式来完成(注意,匿名方法可以忽略参数,Lambda表达式不具备这个特性)。


跟匿名方法类似,Lambda表达式有特殊的转换规则:表达式的类型本身并非委托类型,但它可以通过隐式或显式的发那个是转换为一个委托实例。匿名函数这个术语同时涵盖了匿名方法和Lambda表达式。


下面看看使用Lambda表达式获得字符串长度的例子,通过Lambda将得到更见简洁、易读的代码:


"=>"是C# 3.0新增的,告诉编译器我们正在使用Lambda表达式。"=>"可以读作"goes to",所以例子中的Lambda表达式可以读作"str goes to str.Length"。从例子中还可以看到,根据Lambda使用的特殊情况,我们可以进一步简化Lambda表达式。


Lambda表达式大多数时候都是和一个返回非void的委托类型配合使用(例如Func)。在C# 1.0中,委托一般用于事件,很少会返回什么结果。在LINQ中,委托通常被视为数据管道的一部分,接受输入并返回结果,或者判断某项是否符合当前的筛选器等等。


通过ILSpy查看上面的例子,可以发现Lambda表达式就是匿名方法,是编译器帮我们进行了转换工作,使我们可以直接使用Lambda表达式来进一步简化创建委托实例的代码。



前面简单的介绍了什么是Lambda表达式,下面通过一个例子进一步了解Lambda表达式。


在前面的文章中,我们也提到了一下List的方法,例如FindAll方法,参数是Predicate类型的委托,返回结果是一个筛选后的新列表;Foreach方法获取一个Action类型的委托,然后对每个元素设置行为。下面就看看在List中使用Lambda表达式:


从上面例子可以看到,当我们要经常使用一个操作的时候,我们最好创建一个委托实例,然后反复调用,而不是每次使用的时候都使用Lambda表达式(例如例子中的printer委托实例)。


相比C# 1.0中的委托或者C# 2.0的匿名函数,结合Lambda表达式,对List中的数据操作变得简单,易读。


表达式树也称表达式目录树,将代码以一种抽象的方式表示成一个对象树,树中每个节点本身都是一个表达式。表达式树不是可执行代码,它是一种数据结构。


下面我们看看怎么通过C#代码建立一个表达式树。


System.Linq.Expressions命名空间中包含了代表表达式的各个类,所有类都从Expression派生,我们可以通过这些类中的静态方法来创建表达式类的实例。Expression类包括两个重要属性:


下面看一个构建表达式树的简单例子:


代码的输出为:



通过例子可以看到,我们构建了一个(6+3)的表达式树,并且查看了各个节点的Type和NodeType属性。


Expression有很多派生类,有很多节点类型。例如,BinaryExpression就代表了具有两个操作树的任意操作。这正是NodeType属性重要的地方,它能区分由相同的类表示的不同种类的表达式。其他的节点类型就不介绍了,有兴趣可以参考MSDN。


对于上面的例子,可以用下图描述生成的表达式树,值得注意的是,"叶子"表达式在代码中是最先创建的,,表达式是自下而上构建的。表达式是不易变的,所有可以缓存和重用表达式。



?


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇谈谈对.NET开源框架Castle的认识 下一篇树莓派 安装 OpenCV 使用CMake 编..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: