Scott Guthrie 博客中文版

Scott Guthrie's Blog on ASP.NET and .NET (英文原版地址:http://weblogs.asp.net/scottgu)

   博客堂 :: 首页 :: 联系 :: RSS 2.0 ::
随笔 - 238, 评论 - 1129, 引用 - 436

导航

标签

每月存档

最新留言

广告

 

【原文地址】New "Orcas" Language Feature: Lambda Expressions
【原文发表日期】 Sunday, April 08, 2007 4:21 PM

上个月我开始了一个贴子系列,讨论作为Visual Studio和.NET框架Orcas版本一部分发布的一些新的VB和C#语言特性。下面是这个系列的前2篇贴子:

今天的贴子讨论另一个基础性的新语言特性:Lambda表达式

什么是Lambda表达式?

随VS 2005发布的C#2.0引进了匿名方法的概念,允许在预期代理(delegate)值的地方用“行内(in-line)”代码块(code blocks)来做替代。

Lambda表达式为编写匿名方法提供了更简明的函数式的句法,但结果却在编写LINQ查询表达式时变得极其有用,因为它们提供了一个非常紧凑的而且类安全的方式来编写可以当作参数来传递,在以后作运算的函数。

Lambda表达式的例子:

在我以前的扩展方法博客贴子里,我演示了你如何可以象下面这样声明一个简单的Person类:

然后,我示范了你可以如何使用一些值来生成一个List<Person>集合的实例,然后使用由LINQ提供的新的Where和Average扩展方法来返回集合中的人的一个子集,以及计算这个集合中的人的平均年龄:

上面高亮标记的红色 p => 表达式就是Lambda表达式。在上面的例子里,我用第一个lambda来指定获取特定人时所用的过滤条件,用第二个lambda来指定在计算平均年龄时该用Person对象的哪个值。

详解Lambda表达式

理解Lambda表达式最容易的方法是把它们设想成编写简明的行内方法的方式。譬如,我上面编写的例子可以使用C#2.0的匿名方法来编写,象这样:

上面两个匿名方法都接受一个Person类型的参数。第一个匿名方法返回一个布尔值,表示Person的LastName是否是Guthrie,第二个匿名方法返回一个整数值(返回那个人的年龄)。我们前面使用的lambda表达式的作用是一样的,两个表达式都接受一个Person类型的参数。第一个lambda表达式返回一个布尔值,第二个返回一个整数。

在C#里,一个lambda表达式在句法上是写成一个参数列表,随后是 => 符号,随后是表达式在调用时要运算的表达式或者语句块:

params => expression

所以,当我们编写这样的lambda表达式时:

p => p.LastName == "Guthrie" 

我们是想表示,我们在定义的Lambda接受一个参数p,要运行的代码表达式返回p.LastName的值是否等于“Guthrie”。 我们将参数命名为p是不相干的,我也可以很容易地将其命名为o,x,foo,或者我想要的任何名字。

不象匿名方法要求参数类型是明确地指明的,Lambda表达式允许省略参数类型,而允许它们根据用法来推断出类型。譬如,当我编写 p=>p.LastName == "Guthrie" 这个lambda表达式时,编译器推断出p参数属于Person类型,因为当前的Where扩展方法的对象是个范型的List<Person>集合。

Lambda参数的类型可以在编译时和被Visual Studio的intellisense引擎推断出来,这意味着在编写lambda时你将获得完全的intellisense 和编译时检查。譬如,注意当我在下面健入 p.  时,Visual Studio Orcas是如何提供intellisense完成的,因为它知道 p 是 Person类型:

注: 假如你要给一个Lambda表达式明确地声明参数的类型的话,你可以在Lambda参数表里的参数名字前声明参数类型,象这样:

针对框架开发人员的高级内容:Lambda表达式树 (Lambda Expression Trees)

从一个框架开发人员(framework developer)的角度来看,使得Lambda表达式特别强有力的事情之一是,它们既可以以基于IL的方法的形式被编译成代码代理(code delegate),或者也可以编译成一个表达式树(expression tree)对象,然后在运行时用来分析,转换或者优化表达式。

能将Lambda表达式编译成一个表达式树对象是个强大无比的机制,将促成许多使用场景,包括使用能提供编译时句法检查和VS intellisense的统一的查询语言来建立支持丰富数据查询的高性能对象映射器(无论是关系数据库,活动目录,还是web服务)之能力。

从Lambda表达式到代码代理 (Code Delegates)

上面的Where扩展方法是个将Lambda表达式编译成代码代理(code delegate)的例子(意即它是编译成IL的,可以以代理的形式调用)。支持象上面那样过滤任何IEnumerable集合的Where()扩展方法可以使用下面这样的扩展方法代码来实现:

上面的Where()扩展方法接受一个 Func<T, bool> 类型的过滤参数,该参数是个接受一个类型为T的参数,返回一个布尔值表示条件是否满足的方法之代理。当我们把Lambda表达式作为一个参数传递给这个Where() 扩展方法时,C#编译器会将我们的Lambda表达式编译成IL方法代理(这里,<T> 将是Person),然后我们的Where()方法可以调用来计算某个给定条件是否被满足了。

从Lambda表达式到表达式树

当我们要想针对类似我们的列表集合一样的内存中的数据做运算时,把lambda表达式编译成代码代理是恰如其分的。但考虑一下你想要查询数据库里的数据的情形(下面的代码是使用Orcas中内置的LINQ到SQL对象关系映射器写成的) :

这里,我要从数据库里取出一串强类型的Product对象,我向Where()扩展方法表示,要通过一个Lambda表达式来做过滤。

绝对不想要看到发生的是,从数据库里取回所有的产品记录,将它们放在一个局部的集合里,然后在内存里对它运行Where()扩展方法来进行过滤。这么做效率极其不高,对大数据库的扩缩性将是极差的。而我希望的是,LINQ到SQL的ORM将我上面的Lambda过滤条件翻译成SQL表达式,然后在远程的数据库里进行过滤性查询。那样的话,我只返回那些符合查询条件的记录,这样的数据库查询效率是非常高的。

框架开发人员可以通过声明他们的Lambda表达式参数是个Expression<T>类型,而不是Func<T>类型来取得这样的结果。这会导致Lambda表达式参数被编译成一个我们可以在运行时拆开和分析的表达式树:

注意上面我是怎么把我们在先前用过的同样的 p=>p.LastName == "Guthrie" Lambda表达式,但这次将其赋值给一个 Expression<Func<Person, bool>> 变量,而不是Func<Person,bool> 变量。编译器不会产生IL,而是会指派一个表达式树对象,然后我作为一个框架开发人员就可以用它来对相应的Lambda表达式进行分析,按我想要的方式对其进行运算(譬如,我可以挑出表达式中的类型,名字和值等)。

在LINQ到SQL的情形下,它会将这个Lambda过滤语句翻译成标准的关系SQL语句,来对数据库进行操作(从逻辑上来说,一个“SELECT * from Products where UnitPrice < 55”语句)。

IQueryable<T> 接口

为帮助框架开发人员建立可查询的数据提供器,LINQ提供了 IQueryable<T> 接口。这个接口实现了标准的LINQ扩展方法查询运算符,提供了一个更便利的方式来实现对一个复杂的表达式树的处理(譬如,象下面这样,我用了3个不同的扩展方法,2个lambda来从数据库取回10个产品的情形):

想阅读一些关于如何使用 IQueryable<T> 来建立自定义的LINQ数据提供器的精彩博客系列的话,请看一下下面这些别人写的精彩博客贴子:

结语

希望上面的贴子内容对如何考虑和使用Lambda表达式提供了基本的理解。当与Orcas中System.Linq命名空间下提供的内置标准查询扩展方法结合使用时,它们提供了一个非常好的方式来对任何类型的数据进行查询和交互,同时还保持了对完整的编译时检查和intellisense的支持。

通过利用由Lambda提供的对表达式树的支持,以及 IQueryable<T> 接口,构建数据提供器的框架开发人员可以确保开发人员编写的干净的编码,对任何数据源(无论是数据库,XML文件,内存中的对象,web服务,LDAP系统等)运行起来速度快而且效率高。

在下几个星期里,我将完成这个从理论的层次上讨论新核心语言概念的语言系列,然后转到讨论一些极其实用的实战例子(特别是针对数据库和XML文件使用LINQ的场景)。

希望本文对你有所帮助,

Scott

标签: , , ,

打印 | 张贴于 2007-04-09 23:08:00 | Tag:ASP.NET  .NET  LINQ  Data

留言反馈

#re:新Orcas语言特性:Lambda表达式 编辑
2009-11-06 07:16:10 | billzwm
#Visual Studio 2008 和 .NET 3.5 发布了 编辑
【原文地址】VisualStudio2008and.NET3.5Released 【原文发表日期】Monday,November19,200710:34AM 今天我们发布...
2008-01-25 19:33:00 | [匿名:宏宇]
#ASP.NET MVC框架 (第二部分): URL路径选择 编辑
【原文地址】 ASP.NET MVC Framework (Part 2): URL Routing 【原文发表日期】 Monday, December 03, 2007 2:44 AM 上个月,我发表了我要撰写的系列贴子中的
2008-01-19 02:18:00 | [匿名:ASP.NET Chinese Blogs]
#C# 3.0 的Lambda表达式(Lambda Expressions)【转】 编辑
Lambda表达式(拉姆达表达式)和匿名方法其实是一件事情。唯一的不同是:他们语法表现形式不同。Lambda表达式是在语法方面的更进一步的进化。在本质上,他们是一件事情。他们的作用都是:产生...
2008-01-10 17:18:00 | [匿名:剑飘红]
#VS 2008 和 .NET 3.5 Beta 2 发布了 编辑
我非常高兴地宣布,VS 2008和.NET 3.5的Beta2版本可以下载了。你可以在这里下载Visual Studio 2008产品。你也可以在这里下载较小的VS 2008 Express版本。
2008-01-08 16:33:00 | [匿名:小鱼儿]
#Visual Studio 2008 和 .NET 3.5 发布了 编辑
【原文地址】VisualStudio2008and.NET3.5Released 【原文发表日期】Monday,November19,200710:34AM 今天我们发布...
2008-01-08 16:00:00 | [匿名:吴华朋]
#C# 3.0 的Lambda表达式(Lambda Expressions) 编辑
Lambda表达式(拉姆达表达式)和匿名方法其实是一件事情。唯一的不同是:他们语法表现形式不同。Lambda表达式是在语法方面的更进一步的进化。在本质上,他们是一件事情。他们的作用都是:产生...
2008-01-07 17:03:00 | [匿名:幸福]
#Visual Studio 2008 和 .NET 3.5 发布了 编辑
【原文地址】VisualStudio2008and.NET3.5Released 【原文发表日期】Monday,November19,200710:34AM 今天我们发布...
2008-01-05 08:43:00 | [匿名:幸福]
# C# 3.0 的Lambda表达式(Lambda Expressions) 编辑
Lambda表达式(拉姆达表达式)和匿名方法其实是一件事情。唯一的不同是:他们语法表现形式不同。Lambda表达式是在语法方面的更进一步的进化。在本质上,他们是一件事情。他们的作用都是:产生...
2007-12-17 12:26:00 | [匿名:csdnexpert]
#C#3.0介绍 编辑
以下资源仅供大家参考: 1、自动属性,对象初始化器,和集合初始化器 2、新Orcas语言特性:扩展方法 3、新Orcas语言特性:Lambda表达式 4、新Orcas语言特性:查询句法...
2007-11-27 18:19:00 | [匿名:曹振华]
#C#3.0介绍 编辑
以下资源仅供大家参考: 1、自动属性,对象初始化器,和集合初始化器 2、新Orcas语言特性:扩展方法 3、新Orcas语言特性:Lambda表达式 4、新Orcas语言特性:查询句法...
2007-11-27 18:19:00 | [匿名:曹振华]
#Visual Studio 2008 和 .NET 3.5 发布了 编辑
转自:http://blog.joycode.com/scottgu/archive/2007/11/20/111568.aspx
2007-11-27 17:53:00 | [匿名:曹振华]
#Visual Studio 2008 和 .NET 3.5 发布了 编辑
今天我们发布了VisualStudio2008和.NET3.5。你可以使用下面的链接下载其最终版: 如果你是MSDN订阅者,你可以在MSDN订阅网站下载(注:其中...
2007-11-20 16:44:00 | [匿名:大口仔]
#Visual Studio 2008 和 .NET 3.5 发布了 编辑
转自:http://blog.joycode.com/scottgu/archive/2007/11/20/111568.aspx
2007-11-20 15:19:00 | [匿名:Randy0528]
#VS 2008 和 .NET 3.5 Beta 2 发布了(转帖) 编辑
VS 2008 和 .NET 3.5 Beta 2 发布了(转帖)
2007-09-06 22:38:00 | [匿名:IMustDo]
#回复: 新Orcas语言特性:Lambda表达式 编辑
Lambda 早就在Lisp语言中使用了40多年了
2007-09-04 11:43:00 | [匿名:Creek]
#C#3.0美文收集 编辑
今天在蝈蝈俊.net上看到一个关于.net3.0好文章收集的帖子,就顺手转了过来。 另外我又加了李建忠老师C#3.0锐利体验系列课程的链接,以后如果发现好的 将会继续更新。 大家如果有什么好的文章...
2007-09-01 22:33:00 | [匿名:张荣华]
#回复: 新Orcas语言特性:Lambda表达式 编辑
good!!!
2007-08-30 09:50:00 | [匿名:zhengkep2p]
#新Orcas语言特性:查询句法 编辑
新Orcas语言特性:查询句法
2007-08-22 10:08:00 | [匿名:BoardPung]
#关于 Orcas 信息收集 编辑
本节收集关于Orcas的信息,便于以后学习和交流。
2007-08-21 10:41:00 | [匿名:SmartSoft]
#VS 2008 和 .NET 3.5 Beta 2 发布了 编辑
VS2008和.NET3.5Beta2发布了 【原文地址】VS2008and.NET3.5Beta2Released【原文发表日期】Thursday,July...
2007-08-17 13:52:00 | [匿名:ejiyuan]
# 编辑
Lambda表达式(拉姆达表达式)和匿名方法其实是一件事情。唯一的不同是:他们语法表现形式不同。Lambda表达式是在语法方面的更进一步的进化。在本质上,他们是一件事情。他们的作用都是:产生...
2007-08-15 15:58:00 | [匿名:迭戈]
#VS 2008 和 .NET 3.5 Beta 2 发布了 编辑
【原文地址】 VS 2008 and .NET 3.5 Beta 2 Released 【原文发表日期】 Thursday, July 26, 2007 2:11 PM 我非常高兴地宣布,VS 2008和
2007-07-30 12:17:00 | [匿名:Joycode@Ab110.com]
#回复: 新Orcas语言特性:Lambda表达式 编辑
MS要在C# 3.0里引入更多functional programming的特性了……C#真是逐渐变成一个语言特性的大杂烩。上面看到有人说拉姆达表达式,感觉很有趣。可能用.net的人都不怎么关心函数式语言,其实这种lambda表达式,几十年前就有了,最早可能是在lisp里出现。
2007-07-26 15:35:00 | [匿名:drdirac]
#周末学习总结 编辑
初略了解了ASP.NETAJAX技术及现状;了解了C#3.0的各项新特性;自动属性publicstringName{get;set;}匿名类型new{}对象初始化器new{Name=...
2007-07-08 20:05:00 | [匿名:yicone]
#C# 3.0 的Lambda表达式(Lambda Expressions) 编辑
Lambda 表达式(拉姆达表达式) 和 匿名方法 其实是一件事情。唯一的不同是:他们语法表现形式不同。Lambda 表达式是在语法方面的更进一步的进化。在本质上,他们是一件事情。他们的作用都是:产生方法
2007-06-12 11:05:00 | [匿名:Joycode@Ab110.com]
#C# 3.0 的Lambda表达式(Lambda Expressions) 编辑
Lambda 表达式(拉姆达表达式) 和 匿名方法 其实是一件事情。唯一的不同是:他们语法表现形式不同。Lambda 表达式是在语法方面的更进一步的进化。在本质上,他们是一件事情。他们的作用都是:产生方法。即:内联方法。 引用自 C#首席架构师Anders Hejlsberg 的原话: http://www.ondotnet.com/pub/a/dotnet/2005/10/31/interview-with-anders-hejlsberg-part-2.html?page=2
2007-06-12 10:15:00 | [匿名:ghj1976]
#LINQ篇:查询句法[转] 编辑
2007-04-25 20:47:00 | [匿名:MonkRui]
#[不搜集不行]新Orcas语言特性:查询句法 编辑
fromhttp://weblogs.asp.net/scottgufromhttp://blog.joycode.com/scottgu/archive/2007/04/24/101654.as...
2007-04-24 22:43:00 | [匿名:ColdDog]
#回复: 新Orcas语言特性:Lambda表达式 编辑
上页图片中的是什么字体呀
2007-04-16 22:56:00 | [匿名:一恒]
#回复: 新Orcas语言特性:Lambda表达式 编辑
别急,Orcas Beta1马上就要Release了。
2007-04-11 00:29:00 | [匿名:Boler Guo]
#新Orcas语言特性:Lambda表达式 编辑
什么是Lambda表达式?Lambda表达式为编写匿名方法提供了更简明的函数式的句法,但结果却在编写LINQ查询表达式时变得极其有用,因为它们提供了一个非常紧凑的而且类安全的方式来编写可以当作参数来传递,在以后作运算的函数。
2007-04-10 13:40:00 | [匿名:shoutor]
#回复: 新Orcas语言特性:Lambda表达式 编辑
MS不是打算做一个集大成者吧?

Lambda最早在python中看过
2007-04-10 13:04:00 | [匿名:kwklover]
#回复: 新Orcas语言特性:Lambda表达式 编辑
这个Orcas啥时候能出正式版呐?
2007-04-10 09:45:00 | [匿名:cnodin]
#回复: 新Orcas语言特性:Lambda表达式 编辑
真COOL啊
2007-04-10 09:34:00 | [匿名:仁面寿星]
#回复: 新Orcas语言特性:Lambda表达式 编辑
cool
2007-04-10 08:42:00 | [匿名:失踪的月亮]
#回复: 新Orcas语言特性:Lambda表达式 编辑
cool
2007-04-10 08:42:00 | [匿名:失踪的月亮]
#回复: 新Orcas语音特性:Lamdba表达式 编辑
cool得一塌糊涂~~
2007-04-09 23:16:00 | [匿名:VincentChen]
博客主人设置本博客不允许匿名用户发表言论,请登录后再试