[.net 面向对象程序设计进阶] (5) Lamda表达式(一) 创建委托 本节导读: 通过学习Lambda表达式,学会创建委托和表达式目录树,深入了解Lambda的特性,让你的代码变的更加清晰、简洁、高效。 读前必备: 本节学习前,需要掌握以下知识: A.泛型 (请参考[.net 面向对象编程基础] (18) 泛型) B.Linq基础 (请参照[.net 面向对象编程基础] (19) LINQ基础) C.Linq使用 (请参照[.net 面向对象编程基础] (20) LINQ使用) D.委托 (请参照[.net 面向对象编程基础] (21) 委托) E.事件 (请参照[.net 面向对象编程基础] (22) 事件) 通过《.net 面向对象编程基础》系列中相关介绍,我们已经初步使用过了Lambda表达式进行Linq查询,这节我们主要深入了解Lambda表达式。1. 关于Lambda Lambda 表达式是一种可用于创建委托或表达式目录树类型的匿名函数。 以上是微软对Lambda表达式的定义。从这个定义中,我们可以看出,Lambda的存在,主要做两件事: A.创建委托(Delegate) B.创建表达式树(Expression Tree) 此外,Lambda表达式的本质就是匿名方法(或叫匿名函数)。 后面面我们分别从这两个方法入手,进一步学习Lambda带我给我们的便利。 2. Lambda表达式 Lambda表达式的构成如下: 零个参数: ()=>expr 一个参数:(param)=>expr 或 param=>expr 多个参数:(param-list)=>expr 所有Lambda表达式都使用Lambda运算符=>,该运算符读作"goes to" 当参数只有一个时,右边的括号可以省略。 下面是写法举例://零个参数() =>MethodName()//一个参数(x) => x+xX=>x+x//两个及以上参数(m,n) => m.Length>n//显式类型参数(intx,stringy)=>y.Length>x上面的示例中,其中显式类型参数,是当编译器无法推断其参数类型时,可以显式的定义参数类型。 3. Lambda语句Lambda语句和Lambda表达式类似,只是右边部分写在{}中Lambda语句构成如下:(input parameters) => {statement;}示例:delegatevoidTestDelegate(strings);…TestDelegate myDel= n => {strings = n +""+"World"; Console.WriteLine(s); };myDel("Hello");4.异步Lambda(async和await)我们通过在《.net 面向对象编程基础》中学习,了解了事件本身也是一种特殊的委托,那么Lambda可用于创建委托也就是说同样可以来创建事件。下面看示例:首先看一个普通按钮点击事件的实现及Lambda语句写法下面是普通写法:this.myButton.Click +=newSystem.EventHandler(this.myButton_Click);//事件通常委托写法privatevoidmyButton_Click(objectsender, EventArgs e){MessageBox.Show("您好,我是按钮点击事件!");}下面是Lambda写法://事件Lambda语句写法myButton.Click += (sender, e) => { MessageBox.Show("您好,我是按钮点击事件!这是Lambda语句写法"); };上面两种写法,我们在前面的章节中已经有很多例子了。下面我们看一下异步的事件://异步事件普通写法privateasyncvoidasyncButton_Click(objectsender, EventArgs e){awaitMyMethodAsync();MessageBox.Show("您好,我是按钮点击事件!异步的哟!");}asyncTask MyMethodAsync(){awaitTask.Delay(1000);}我们用Lambda来改写上面的异步事件://异步事件Lambda写法asyncButton.Click +=async(sender, e) => {awaitMyMethodAsync(); MessageBox.Show("您好,我是按钮点击事件!异步的哟!这是Lambda语句写法"); };asyncTask MyMethodAsync(){awaitTask.Delay(1000);}上面的异步事件,就是在事件委托阶段使用async来表示这是一个异步的,在事件处理中阶段使用await关键词来指定一个异步方法。Lambda语句写法同样是针对异步事件的简洁写法,具有相同的效力。5. 标准查询运算的Lambda表达式5.1泛型委托 使用Lambda我们在[.net 面向对象编程基础] (21) 委托一节中说到了三种常用的泛型委托Action(无返回值泛型委托)Func(有返回值泛型委托)predicate(返回值为bool型的泛型委托)这节不再重复说明泛型委托,不熟悉泛型委托的小伙伴,请参考,我们只举例说明泛型委托和它的Lambda写法//Action 无返回值类型的 泛型委托//匿名方法声明及调用Action act =delegate(inta,intb) {Console.WriteLine(a+"+"+ b +"="+ (a +b));};act(11,22);//表达式声明及调用Action actLambda = (a, b) => { Console.WriteLine(a +"+"+ b +"="+ (a +b)); };actLambda(111,222);//Func 带返回值的 泛型委托//匿名方法声明及调用Func acc =delegate(inta,intb) {return(a +"+"+ b +"="+ (a +b));};Console.WriteLine(acc(11,22));//表达式声明及调用Func ac = (a, b) => {return(a +"+"+ b +"="+ (a +b)); };Console.WriteLine(ac(111,222));5.2 Linq中使用Lambda关于在Linq中使用Lambda表达式,我们在[.net 面向对象编程基础] (20) LINQ使用有详细说明了,不熟悉的小伙伴请参考,下面我们举例说明几种常用的Lambda查询写法。5.2.1 Count 求数量//查询下列数中的奇数 - Lambda写法int[] numbers = {5,4,1,3,9,8,6,7,2,0};intoddNumbers = numbers.Count(n => n %2==1);Console.WriteLine("奇数有:"+oddNumbers.ToString()+"个,Lambda写法");//查询下列数中的奇数 -Linq查询写法varoddNumbersFunc = (fromnuminnumberswherenum %2==1selectnum).Count();Console.WriteLine("奇数有:"+ oddNumbersFunc.ToString() +"个,Linq查询写法");运行结果如下:5.2.2 TakeWhile 满足条件就返回集合//TakeWhile只要满足指定的条件就返回,在检检到number中的6时,就返回,其中8 和9 不满足条件,则返回 5 4 1 3int[] numbers = {5,4,1,3,9,8,6,7,2,0};varfirstNumbersLessThan6 = numbers.TakeWhile(n => n <6);Console.WriteLine("满足条件就返回的数有:"+ firstNumbersLessThan6.Count().ToString() +"个,Lambda写法");//第二个参数index表示n的索引位置stringNewNumber =String.Empty;numbers.TakeWhile((n, index)=> n >= index).ToList().ForEach(m=> NewNumber+=m +"");Console.WriteLine("满足条件就返回的数有:"+ NewNumber +",Lambda写法"); 运行结果如下:6. Lambda的类型推理在编写 lambda 时,通常不必为输入参数指定类型,因为编译器可以根据 lambda 主体、参数的委托类型以及 C# 语言规范中描述的其他因素来推断类型。 对于大多数标准查询运算符,第一个输入是源序列中的元素类型。 因此,如果要查询 IEnumerable,则输入变量将被推断为 Customer 对象,这意味着你可以访问其方法和属性://Lambda的类型推理List list =newList() {newMyClass(){ at1 ="aaa", at2 =2, at3 =DateTime.Now},newMyClass{ at1 ="bbb", at2 =5, at3 = DateTime.Parse("2015-06-07") },newMyClass{ at1 ="aaa", at2 =1, at3 = DateTime.Parse("2010-11-12") }};Console.WriteLine("at1为aaa的元素有:"+ list.Where(m => m.at1 =="aaa").Count() +"个,Lambda写法"); classMyClass {publicstringat1 {get;set; }publicintat2 {get;set; }publicDateTime at3 {get;set; }}运行结果如下:Lambda 的一般规则如下:A. Lambda 包含的参数数量必须与委托类型包含的参数数量相同。B. Lambda 中的每个输入参数必须都能够隐式转换为其对应的委托参数。C. Lambda 的返回值(如果有)必须能够隐式转换为委托的返回类型。请注意,lambda 表达式本身没有类型,因为常规类型系统没有“Lambda 表达式”这一内部概念。但是,有时以一种非正式的方式谈论 lambda 表达式的“类型”会很方便。 在这些情况下,类型是指委托类型或 lambda 表达式所转换到的 Expression 类型。7. Lambda表达式的变量范围我们在[.net 面向对象编程基础] (19) LINQ基础 一节中说到匿名方法时提到匿名方法可以引用满园内的外部变量,前面示例中也有提及。下面我们看一个示例: classProgram{staticintnum =2;staticvoidMain(string[] args){intnum2 =7;//Lambda表达式的变量范围//相对以下表达式内部,一个类的字段num和一个变量num2,下面测试在表达式内部调用int[] numbers2 = {5,4,1,3,9,8,6,7,2,0};//我们对大于num小于num2的数求和intsum = numbers2.Where(m => m > num && m <如果对你有帮助,记得点一下推荐哦,如有有不明白或错误之处,请多交流> <对本系列文章阅读有困难的朋友,请先看《.net 面向对象编程基础》><转载声明:技术需要共享精神,欢迎转载本博客中的文章,但请注明版权及URL>.NET 技术交流群:467189533 ============================================================================================== 本文链接:[.net 面向对象程序设计进阶] (5) Lamda表达式(一) 创建委托,转载请注明。