在C#2中,由于有了方法组,匿名方法,类型的协变和抗变,使得运用delegate变得很容易,在注册事件时代码变得简单易读,但是在C# 2中,代码仍然有点臃肿,大块的匿名方法会降低代码的可读性,一般我们不会在一条语句中写多个匿名方法。

LINQ产生的一个目的是能够方便的对数据进行管道操作而不失语义。LINQ能够表达对数据进行的各种逻辑操作,LINQ执行时,这些操作实际上都是通过委托来实现的。使用LINQ to Object操作数据时,一条语句中包含多个委托是很常见的,C# 3中的Lambda表达式正式这幕后的功臣,它不仅使得我们能够在一条代码中写多个委托,而且不会丧失代码的可读性。相信用过LINQ的人应该都有这样的体会。

在很多方面Lambda表达式可以看成是C#2中匿名方法的演变。他们俩的功能是一样的,都使得代码更加清晰和紧凑。另外,Lambda表达式和匿名方法在闭包的特性上是一致的,但是Lambda表达式还有一些小的特性,能够使得代码在大多数情况下更加紧凑。和匿名方法一样,Lambda表达式有着自己的转换规则---表达式的类型并不是一个委托的类型,但是它可以显示或者隐式的转换为一个委托的实例。

下面来看看Lambda表达式是如何来表示委托的。我们先从一个简单的例子开始。首先我们写一个以String类型为参数,返回Int32类型的值的委托实例。然后演示委托如何一步一步转换为Lambda表达式。

一、Func<……>泛型委托类型

首先我们要选委托类型,在.NET 3.5中,提供了一系列泛型委托类型。在.NET3.5中有5个名为Func的泛型委托类型。每一个类型里面包含0至4个类型参数。5个Func泛型类型签名如下:

TResult Func<TResult>()
TResult Func<T,TResult>(T arg)
TResult Func<T1,T2,TResult>(T1 arg1, T2 arg2)
TResult Func<T1,T2,T3,TResult>(T1 arg1, T2 arg2, T3 arg3)
TResult Func<T1,T2,T3,T4,TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4)

尖括号中的,都是类型参数,例如,Func<String,Double,Int32> 表示该委托接受两个参数,第一个是String,第二个是Double,返回Int32类型,所有适合该类型的方法都可以使用该委托。Func<String,Double,Int32>等价如下面的委托:

public delegate Int32 SomeDelegate(String arg1, Double arg2)

.NET 3.5中还有一个名为Action<……>的泛型委托类,他的用法和Func的差不多,只是他的返回值为void。如果您觉得5个参数不够用的话,在.NET 4.0中,Action<……>和Func<……>的参数扩展到了16个,如Func<T1,……,T16,TResult>,这么多的参数主要是为了支持DLR。

在我们这个例子中,我们需要一个类型,他接受String作为参数,返回Int32类型的值,所以我们可以使用Func<String,Int32>。

二、转化为Lambda表达式的第一步

根据上面的委托类型,我们可以使用匿名方法创建一个委托实例。如下,该实例返回String参数的长度。

Func<String, Int32> returnLength;
returnLength = delegate(String text) { return text.Length; };
Console.WriteLine(returnLength("Hello"));

上面的例子中,将输出5. 上面的以delegate开头的是匿名表达式。现在我们开始对这部分进行转换。最常见的Lambda表达式的形式如下:

(参数类型1 参数名1 [ , 参数类型2 参数名2 ……]) => { 方法内部表达式 }

=>是在C# 3中引入的,他告诉编译器,我们将使用Lambda表达式,大多数的使用Lambda表达式代表委托的方法都有一个返回值。但在C# 1中,委托通常用于事件,所以很少有返回值。在LINQ中,委托用做数据管道的一部分,使得数据能够进行各种映射,过滤等操作。

下面我们使用Lambda表达式来表示该委托的实例,代码如下:

Func<String, Int32> returnLength;
returnLength = (String text)=> { return text.Length; };
Console.WriteLine(returnLength("Hello"));

上面的例子返回的结果和之前的一样,在大括号中,我们可以写任意表达式,只要返回值为String类型。

三、使用单个表达式作为函数体

前面的例子中,我们使用一对大括号将返回值表达式括起来了。这样做很灵活,你可以在括号内写多条语句,进行各种操作,就像在匿名方法中的那样。但是大多数情况下,通常可以将这个函数体表示为单个表达式,这个表达式的值就是Lambda表达式的值。在这种情况下,我们可以省去左右的大括号和逗号,表达式样子下面的样子。

(参数类型1 参数名1 [ , 参数类型2 参数名2 ……]) =>方法表达式

这样,上面例子中的右边部分可以改写为:

returnLength = (String text) => text.Length;

现在看起来简洁多了。那参数类型怎么办呢,由于编译器已经知道他是Func<String,Int32>的一个实例,该实例接受一个String类型的参数,所以我们可以直接将参数卸载括号内,从而省略参数类型。

四、隐式类型参数列表

在大多数情况下,编译器能够推断出参数的类型,而不需要我们现实的去声明,因此,Lambda表达是可以改写为:

(参数名1 [ ,参数名2 ……]) =>方法表达式

隐式类型参数列表,就是一系列用逗号分隔的参数名称。这些参数类型,要么全部都显示声明类型,要么全部不声明类型让编译器推断,不能一部分显示声明,一部分隐式声明。如果有参数类型为out或者in的话,就必须显示声明参数类型。这样我们的Lambda表达式可以改写为:

returnLength = (text) => text.Length;

现在看起来简洁多了。最后唯一一点有点不爽的是,参数有个括号。

五、去掉单参数两侧的括号

当Lambda表达式只有一个参数的额时候,C# 3运行我们省略掉两边的括号,整个Lambda表达式变为下面的形式:

参数名 =>方法表达式

根据这一规则,之前例子中的Lambda表达个可以改为:

returnLength = text => text.Length;

你可能会想,哪有这么多特例啊,参数恰好只有一个,函数主题恰好能用一个表达式表达完。这里是为了展示Lambda表达式如何简化代码提高可读性,很多时候,当大量的这样的情况出现时,使用Lambda表达式能够极大提高代码可读性。现在整个方法可以写成下面这样:

Func<String, Int32> returnLength;
returnLength = text => text.Length;
Console.WriteLine(returnLength("Hello"));

现在看起来简洁多了,可能第一次觉得这样写怪怪的,就像第一次用匿名方法和LINQ那样,用久了就习惯了。当使用Lambda表达式时,你能够体会到在创建一个委托实例时时多磨的简洁。上面例子中,我们可以把变量text换乘其他名字比如x,在LINQ中经常这样,但是长一点的变量可以更加容易阅读。下图总结了以上的步骤:

六、总结

本文以一个特例演示了匿名方法如何一步一步转换为Lambda表达式。从转化中您可以体会到Lambda表达式的简洁,希望这些对您了解Lambda表达式有点帮助。

.NET中的Lambda表达式与匿名方法相关推荐

  1. C# lambda表达式与匿名方法

    文章目录 匿名方法 Lambda表达式 实例 实例 博主写作不容易,孩子需要您鼓励 万水千山总是情 , 先点个赞行不行 C#中的匿名方法是在C#2.0引入的,它终结了声明委托的唯一方法是使用命名方法的 ...

  2. Lambda表达式替代匿名方法

    使用Lambda表达式,"=>"之前为参数列表,如果有多个参数,则不能省略括号,比如:(s,e)=>.... 如果方法有返回值,并且处理代码只有一行,可以简写成i=&g ...

  3. python lambda表达式的使用方法(匿名函数)

    文章目录 lambda函数简介 示例1:将存有文件名的字符串列表,运用正则表达式方法提取文件名中的数字,按照数字大小将文件名字符串列表重新排序 示例2:将存有hsv颜色空间的颜色元组列表,转换成rgb ...

  4. lambda表达式或者匿名函数中为什么要求外部变量为final

    1.参考博客 关于Lambda表达式里面修改外部变量问题 JDK8之前,匿名内部类访问的局部变量为什么必须要用final修饰 2.匿名内部类 在jdk7之前,匿名内部类访问外部类的局部变量时,那么这个 ...

  5. 【Python 必会技巧】lambda 表达式(匿名函数)及其在内置函数中的应用

    lambda 表达式,又称匿名函数,即,函数没有具体的名称,常用来表示内部仅包含 1 行表达式的函数. 使用 lambda 编写的代码更加简洁紧凑,但是 lambda 函数支持的功能却是十分有限的,目 ...

  6. Python中lambda表达式_匿名函数

    lambda表达式和匿名函数 lambda表达式 ​ lambda表达式可以用来声明匿名函数,实际生成一个函数对象. ​ lambda表达式只允许包含一个表达式,该表达式的计算结果就是函数的返回值. ...

  7. Python中的Lambda表达式

    Lambda表达式 (Lambda Expressions) Lambda Expressions are ideally used when we need to do something simp ...

  8. 什么是C ++ 11中的lambda表达式?

    本文翻译自:What is a lambda expression in C++11? What is a lambda expression in C++11? 什么是C ++ 11中的lambda ...

  9. java8的表达式_java8中的Lambda表达式

    lambad表达式是一个匿名函数,既没有函数名的函数.在lambda表达式出现之前,java中更多使用的是匿名内部类所以有些刚刚接触lambda表达式的人会把lambda表达式误认为就是匿名内部类的简 ...

  10. 通俗理解Java中的Lambda表达式

    Lambda Lambda表达式支持将代码块作为方法参数, 允许使用更为简洁的方式实现抽象类或接口的抽象方法, 而不再是通过匿名内部类的方式, 它具有对某一方法重写或实现的功能; 接下来通过一个简单的 ...

最新文章

  1. 关于listView的item失去焦点不能点击 Item中包含Button 导致抢占焦点
  2. CCAI 2019 | Shai Ben-David:人工智能的可学习性能否判定?
  3. POJ 1185 炮兵阵地 状压dp
  4. 360隔离mysql恢复_MySQL备份与恢复
  5. 'demangle.h' file not found
  6. 使用 SAP Uiveri5 遇到 passport 依赖的问题以及解决方案
  7. 全排列及相关扩展算法(三)——利用中介数求排列在字典序排位算法
  8. Java算法之旋转数组
  9. python语言开发环境搭建_Python开发环境搭建-Go语言中文社区
  10. 动态规划之编辑距离问题
  11. 递归求解汉诺塔问题(C++)
  12. java+编写守护线程_学习Java编程-守护线程
  13. 安装axios及其基础用法
  14. 《自己动手写网络爬虫》笔记3-宽度优先遍历互联网
  15. 物联网和边缘部署的5大嵌入式工控机设计要求
  16. java前景以及职业发展方向
  17. 一大波猪年元素的二维码助你跨猪年!
  18. win10自带sftp服务器_高手亲自解决win10系统下怎么使用OpenSSH设置SFTP服务器的完全操作办法...
  19. XPO学习(6)----实现一个简单的留言薄(ASP.NET)
  20. mysql笔记(一):Navicat for MySQL远程连接mysql服务报错的解决方法(1130、2509)

热门文章

  1. 【语音识别】基于matlab MFCC+SVM特定人性别识别【含Matlab源码 533期】
  2. ai/ml_您应该在本周(7月11日)阅读有趣的AI / ML文章
  3. android设置内存大小,Android Studio内存大小的设置
  4. Java-练习1:Bank银行模拟程序(面向对象实现)
  5. 有一些四位数,百位数字都是3,十位数字都是6,并且它们既能被2整除,又能被3整除,求这样的四位数中最大的和最小的两数各是几?
  6. 获取两个数组的差 php,php-获取2个数组之间的差
  7. 计算机网络相关词汇,计算机网络英语词汇
  8. android 圆形图片按钮,Android自定义View圆形图片控件代码详解
  9. mysql动态sql语句_mysql 存储过程中使用动态sql语句
  10. mysql lamp 配置命令总结