台技术设计与应用NET第二章V2.ppt_第1页
台技术设计与应用NET第二章V2.ppt_第2页
台技术设计与应用NET第二章V2.ppt_第3页
台技术设计与应用NET第二章V2.ppt_第4页
台技术设计与应用NET第二章V2.ppt_第5页
已阅读5页,还剩94页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1,电子政务平台技术设计与应用,南大滨海学院法政学系 张一鸣,电子政务平台技术设计与应用 ASP.NET高级应用 Version 2,南大滨海学院法政学系 张一鸣 2016年2月10日,2,ASP.NET高级应用 第2章 C#语言相关特性,南大滨海学院法政学系 张一鸣 2016年2月10日,电子政务平台技术设计与应用,3,本章主要内容,本章主要是回顾和深入介绍在ASP.NET中涉及的C#中高级知识, 包括泛型、匿名、lambda表达式、yield关键字、IEnumerable接口等 。,委托,对象初始化表达式,匿名与匿名方法,Lambda表达式,泛型,扩展方法,枚举量和Yield,查询表达式,4,C#的新特征,对于使用ASP.NET的复杂功能来说,它完全依赖与C#中新增的一些概念和特征,因此可以说,泛型等概念和特征是这些应用的基础。本章将系统的介绍这些内容,包括泛型、lambda表达式、匿名、yield关键字、IEnumerable接口等,为学生完全掌握LINQ技术打好基础。,5,2.1 代理(委托),C#调用方法时,可以向方法传递参数。这些参数分为按值、按引用或按输出等类型。其中引用实际上就是原来变量即实参的别名,指向实参在内存中的位置,所以在方法中对引用类型参数的修改会导致对实参本身的改变。 类似地,如果把方法也看成数据,通过代理机制把方法赋值给一个变量,也就是把这个方法在内存中的位置赋给变量,则通过这个变量就可以把这个方法传递给其他的方法调用。这种类型的变量就是代理类型的变量。,6,代理(委托)的实质,代理本身是一个类,它封装了一个或多个方法。在内部,一个代理保存方法指针(地址)的对照表,即这个代理类里面的每个方法名和它对应的地址的列表。每个方法指针可以与一个引用实例配对,而该实例是包含实例方法的类实例。 声明代理类型时在方法头前面放上关键字delegate,例如 : public delegate void PrintCallback ( int no);,7,例子2.1 代理的应用实例分析,本例是文书自动回信的局部功能演示。根据输入的来信人姓名和性别,确定增加“先生”或“女士”的称呼;根据处理来信时间,确定增加“你好”、“上午好”或“下午好”的问候语。这需要编制添加称呼词的两个方法和添加时间问候词的三个方法。为了在主程序中使代码简洁清晰,不用if语句分情况调用不同称呼词和问候语的办法,而是采用两个代理分别表示添加的内容,问候语的区别通过代理的参数来解决。,8,例子2.1 代理类型的应用,using System; Namespace DemoDelegate1 delegate void myDelegate (string s); /无返回类型 /的代理,添加问候词 delegate string myDelegateStr (string s, bool man); /有返回类型的代理,添加称呼词 class Program static void show1 (string s) Console.WriteLine ( “你好,0!”,s); static void show2 (string s) Console.WriteLine ( “上午好,0!”,s); ,9,例子2.1 代理类型的应用(续1),static void show3 (string s) Console.WriteLine ( “下午好,0!”,s); static string AddTitle ( string s, bool man ) if ( man ) return string.Format ( “你好,0先生!”,s); else return string.Format ( “你好,0女士!”,s); ,10,例子2.1 (续2),static void Main ( string args ) string name = “林晚荣”; string name2 = “徐芷晴”; myDelegate del1 = new myDelegate(show1); Console.WriteLine ( “.NET代理调用” ); del1 (name); /代理调用,del1指向方法show1 Console.WriteLine ( “*” ); Console.WriteLine ( “多路代理绑定调用” ); del1 += show2; /代理del1在已绑定show1基础上又添加 /指向show2 del1 += show3; /代理del1在原基础上又添加指向show3,11,例子2.1 (续3),del1 (name); /代理调用,del1指向方法show1、 /show2、show3 Console.WriteLine ( “n 合并掉show1代理调用” ); del1 -= show1; /代理del1现在仅指向show2、 show3 del1 (name); /代理调用,del1仅指向方法show2和 /show3 Console.WriteLine ( “*” ); myDelegate del2 = AddTitle; Console.WriteLine ( “返回带类型的绑定调用” ); Console.WriteLine ( del2 ( name, true ) ); Console.WriteLine ( del2 ( name2, false ) ); ,12,例子2.1 代理的应用实例运行结果,.NET代理调用 你好,林晚荣! * 多路代理绑定调用 你好,林晚荣! 上午好,林晚荣! 下午好,林晚荣! * 合并掉show1代理调用 上午好,林晚荣! 下午好,林晚荣! * 返回类型的代理调用 你好,林晚荣 先生! 你好,徐芷晴 女士!,13,例子2.2 代理的应用实例分析,本例是对一个有10个元素的整形数组,分别调用三个不同的方法过滤选出其偶数、奇数和大于5的数的子集并显示。为了实现这个目的,一般是分别编写筛选偶数的方法IsEven、筛选奇数的方法IsOdd和筛选大于5的数的方法IsOver5,然后在程序里分别调用它们来实现要求。更简洁的办法是采用代理技术,设计一个代理类型NumPredicate和它的实例对象变量even-Predicate。在主程序每次执行不同的任务时,都是调用同一个代理变量,只是分别给这个代理型变量赋值引用不同的方法。,14,例子2.2 代理的应用实例分析(续),IsEven、IsOdd和IsOver5这三个方法都接收一个整型参数int并判断是否满足条件,然后返回一个布尔型逻辑值。为了解决对数组全部元素过滤挑选的任务,又设计了一个方法FilterArray,它接受待过滤的数组和代理类型NumPredicate的引用变量作为参数,并按照每次引用变量所指向的方法对数组进行具体的过滤操作。对每次选中的结果调用方法DisplayList全部显示出来。本例中采用了列表结构List作为存放选中数组元素结果的保存结构。,15,例子2.2 代理类型的应用,using System; using System.Collection.Generic; class Delegates public delegate bool NumPredicate ( int num ); public static void Main ( ) int number = 1,2,3,4,5,6,7,8,9,10 ; NumPredicate evenPredicate = IsEven; Console.WriteLine (”Call Iseven using a delegate variable:0”, evenPredicate ( 4 ); List evenNumbers = FilterArray ( number, evenPredicate );,16,例子2.2 代理类型的应用(续1),DisplayList (“Use IsEven to filter even numbers”, evenNumbers); List oddNumbers = FilterArray ( number, IsOdd ); DisplayList (“Use IsOdd to filter odd numbers:”, OddNumbers ); List NumberOver5 = FilterArray ( number, IsOver5 ); DisplayList (“Use IsOver5 to filter numbers over 5:”,NumberOver5 ); /end Main method,17,例子2.2 (续2),private static List FilterArray ( int intAr, NumPredicate pred ) List result = new List ( ); foreach ( int item in intAr ) if ( pred ( item ) ) result.Add ( item ); return result; / end method FilterArray private static bool IsOdd ( int number ) return ( number % 2 = 1 ); / end method IsOdd,18,例子2.2 (续3),private static bool IsEven ( int number ) return ( number % 2 = 0 ); / end method IsEven private static bool IsOver5 ( int number ) return ( number 5 ); / end method IsOver5 private static void DisplayList ( string descript, List list ) Console.Write ( descript ); foreach ( int item in list ) Console.Write ( “0 “, item ); Console.WriteLine ( ); / end method DisplayList,19,例子2.2 代理的应用实例运行结果,Call IsEven using a delegate variable: True Use IsEven to Filter even numbers: 2 4 6 8 10 Use IsOdd to Filter odd numbers: 1 3 5 7 9 Use IsOver5 to Filter numbers over 5 : 6 7 8 9 10,20,2.2 对象初始化器,Visual Studio C#2008提供了一个新特性对象初始化器(object initializer),它可以创建对象并在同一语句中将其属性初始化。这适用于类没有提供所需要的构造函数的情况。 采用初始化器时,不能写与类同名的构造方法,而是写一个与类同名的初始化器,即原来构造方法名字后面的圆括号“()”被一组花括号“ ”和类里面变量成员的初始值所代替。,21,对象初始化器的特点,例如,Time1类的默认构造方法: Time1 time = new Time1 ( ); 采用初始化器时就变成: Time1 time = new Time1 Hour=0, Minute=0, Second=0 ; 采用初始化器时,类里面就不能编写任何构造方法。,22,例子2.3 Time类的对象初始化器,public class Time private int hour; /023 private int minute; /059 private int second; /059 public void SetTime ( int h, int m, int s ) hour = ( ( h = 0 ,23,例子2.3 对象初始化器(续1),public string ToUniversalString ( ) return string.Format ( “0:D2:1:D2:2:D2”, hour, minute, second ); public override string ToString ( ) return string.Format ( “0:1:D2:2:D2 3”, ( ( hour = 0 | hour =12 ) ? 12 :hour % 12 ),hour, minute, second, ( hour 12 ? “AM” : “PM” ) ); ,24,例子2.3 程序代码 (续2),public int Hour /属性Hour get return hour; set hour = ( value = 0 ,25,例子2.3 程序代码(续3),using System; public class ObjectInitializerTest public static void Main ( string args ) Console.Write ( “Time object created with object initializer “ ); Time time = new Time Hour = 14, Minute = 145, Second = 12 ; Console.Write ( “Standard time 0: “, time.ToString ( ) ); Console.Write ( “Universal time 0: “, time.ToUniversalString ( ) ); Console.Write ( “Time object created with Minute property set “ ); Time anothertime = new Time Minute = 45 ; Console.Write ( “Standard time 0: “, anothertime.ToString ( ) ); Console.Write (“Universal time 0: “, anothertime.ToUniversalString ( ) ); ,26,例子2.3 程序运行结果:,Time object created with object initializer Standard time: 2:00:12 PM Universal time: 14:00:12 Time object created with Minute property set Standard time: 12:45:00 AM Universal time: 00:45:00 注意:每个属性名只能在对象初始化器表中出现一次。对象初始化器按照每个参数出现的顺序执行属性的初始化。如果对象初始化器中指定的值无效(如Minute = 0145),则set方法强制设其为0。,27,集合初始化器,如果集合实现了泛型System.Collections.Generic-.ICollections接口,并且指定了T的类型,就可以使用集合初始化器来对整个集合初始化。集合初始化器将对集合中的每个元素调用ICollection.Add(T)方法,从而把该元素添加到集合中。 集合初始化器由一系列包括花括号之间的元素初始化器构成,元素初始化器之间使用逗号进行分割。元素初始化器不能是赋值表达式。,28,例子2.4 集合初始化器和 对象初始化器的复合使用,using System; using System.Collections.Generic; namespace DemoInitislizer class Girlfriend /Demo Object public string Name get; set; public int Age get; set; class Boyfriend /Demo Object public string Name get; set; public int Age get; set; public List Girls get; set; /Set Attribute ,29,例子2.4 程序代码(续),public class SetInitializerTest public static void Main ( string args ) List gfs1 = new List “Mary”, “Susan”,”Lucy” ; List gfs2 = new List ( ); gfs2.Add ( “Mary” ); gfs2.Add ( “Susan” ); gfs2.Add ( ”Lucy” ); Boy boy = new Boy Name = “Tom”, Age = 24, Girls = new List new Girlfriend Name = “Mary” , Age =23 , new Girlfriend Name = “Susan” , Age =19 , new Girlfriend Name = “Lucy” , Age =21 ; ,30,例子2.4 程序代码的分析说明,本例中,对于gfs1就是用集合初始化器创建的它等价于gfs2对每一个元素分别调用元素初始化器ICollection.Add(T)方法。 对Boy类的对象boy使用了对象初始化器与集合初始化器的复合使用,用一条语句完成了对多个对象和整个集合的初始化。,31,2.3 匿名类型,匿名类型顾名思义就是没有类的名称,也就是没有类的定义,但是它有类体,可以创建简单类,用于存储数据。 匿名类型声明也称为匿名对象生成表达式,类似于初始化器,其声明的开头是关键字new,然后是成员初始化器列表,放在花括号中。在new后面是不能有类的构造方法名(与类名相同)的。例如: var bob = new Name = “Bob Smith”, Age = 26 ; 声明了一个匿名类对象bob,且其属性Name = “Bob Smith”, Age = 26 。注意这个类没有类名。,32,例子2.5 使用匿名类的例子,using System; class AnonymousTypes static void Main ( ) var bob = new Name = “Bob Smith”, Age = 37 ; Console.WriteLine (“Bob: ”, bob.ToString ( ) ); var steve = new Name = “Steve Jones”, Age = 26 ; Console.WriteLine (“Steve: ”, steve.ToString ( ); Console.WriteLine (“nBob and Steve are 0: ”, (bob.Equals ( steve ) ? “equal” : “not equal” );,33,例子2.5 使用匿名类的例子(续),var bob2 = new Name = “Bob Smith”, Age = 37 ; Console.WriteLine (“nBob2: ”,bob2.ToString ( ); Console.WriteLine (“nBob and Bob2 are 0: ”, ( bob.Equals (steve) ? “equal”:“not equal” ); /end Main method ,34,Bob: Name = Bob Smith, Age = 37 Steve: Name = Steve Jones, Age = 26 Bob and Steve are not equal Bob2: Name = Bob Smith, Age = 37 Bob and Bob2 are equal 分析:上例中使用了隐式类型局部变量保存对匿名类型对象的引用,如var bob = new Name = “Bob Smith”, Age = 37 ; 还用匿名类型的方法ToString ( )在控制台上显示这个对象的信息。编译器在创建匿名类型定义时定义ToString方法,它返回的字符串放在花括号中。 例子中还创建了另一个匿名类对象Steve,其使用的初始化器内容与bob的相同,被认为相同类型。比较两个匿名类对象相等,要检查他们的所有属性(这里是Name和Age),有其中一个不等,则两个匿名类对象不相等。,34,例子2.5运行结果,35,匿名类型的进一步说明,匿名类型一般出现在ADO.NET的select子句中,用来投影筛选出的数据。匿名类型使用new运算符和对象初始值设定项来创建。 匿名类型创建的属性是只读的,匿名类型的名称和属性的数据类型由编译器随机指定或自动推断。,36,匿名类型的进一步说明,匿名类型不允许包含属性以外的成员,不能强制转换为Object以外的类型或接口,如果匿名类型赋值给变量,必须使用var关键字构建此变量。 多个匿名类型具有相同的顺序、相同数量和种类的属性成员,编译器会将这些匿名类型视为相同的类型,并且它们共享编译器生成的类型信息。,37,例子2.6 匿名类型创建类,using System; using System.Linq; using System.Collections.Generic; namespace DemoAnonymousType class Program public static void Main ( string args ) var anonymous1 = /创建匿名类型 new Name = “安碧茹”, Title = “苗族圣姑”,Age = 36 ; var anonymous2 = /创建匿名类型,类型同上 new Name = “宁雨昔”, Title = “圣坊仙子”,Age = 37 ; List lst = new List “高丽公主”, “大华军师”, “霓裳公主” ; Console.WriteLine ( “anonymous1的类型:0”, anonymous1.GetType ( ).Name ); Console.WriteLine ( “0 1 2”,anonymous1.Name, anonymous1.Title, anonymous1.Age );,38,例子2.6 匿名类型创建类(续),Console.WriteLine ( “anonymous2的类型:0”, anonymous2.GetType ( ).Name ); Console.WriteLine ( “0 1 2”, anonymous2.Name, anonymous2.Title, anonymous2.Age ); Console.WriteLine ( “*”); var query = from n in lst /LINQ select子句中创建匿名类型 where n.IndexOf ( “公主” ) -1 select new Name = “查询元素”, Title = n ; / LINQ的select子句把查询到的元素投影成匿名类型 foreach ( var item in query ) Console.WriteLine ( “元素的类型: 0”, item.GetType( ).Name ); Console.WriteLine ( “0 1”, item.Name, item.Title ); ,39,例子2.6 匿名类型创建类的分析,本例用var定义的两个匿名类型对象anonymous1、anonymous2由于属性的类型、顺序相同,所以这两个匿名类型生成的类型也是一致的。 本例在LINQ查询中的的select子句也创建了一个匿名类型,其类型也与上面定义的两个匿名对象的类型是一致的: select new Name = “查询元素”, Title = n ;,40,例子2.6 匿名类型创建类的运行结果,anonymous1的类型: f_AnonymousType03 安碧茹 苗族圣姑 36 anonymous2的类型: _AnonymousType03 宁雨昔 圣坊仙子 37 * 元素的类型: f_AnonymousType12 查询元素 高丽公主 元素的类型: f_AnonymousType12 查询元素 霓裳公主,41,2.4 扩展方法:对现有类增加新方法,有时需要在现有类里面增加新的功能或方法,但是由于受到一些限制又无法对这些类进行修改。就可以利用类的扩展方法在不必修改类的代码的前提下为现有类增加新的功能。 例如,Time类没有显示时间的方法,增加一个扩展方法DisplayTime,它用Time对象的ToString方法在控制台窗口中显示时间。,42,扩展方法的特点(续),新增的DisplayTime方法不必修改Time类的源代码,关键是在其方法头的参数表中的Time对象参数前面添加关键字this。 关键字this告诉编译器DisplayTime方法扩展了现有类。C#编译器将用这个信息把增加的代码插入编译的程序中,使得现有类型可以使用扩展方法。 具体实例参见下面的例子2.7。,43,扩展方法的特点,给已经存在的类型添加方法,除了继承类型外,就要采用扩展方法了。扩展方法是一种建立在非泛型、非嵌套的静态类中特殊的静态方法。 调用扩展方法与调用在类型中实际定义的方法之间没有明显的差异。扩展方法是静态方法,所以无法访问类型的内部成员。 扩展方法的第一个参数的数据类型,决定这个方法应用于哪个类型,在其前面还需标有this关键字。,44,例子2.7 Time类的扩展方法,using System; class TimeExtensionsTest static void Main ( string args ) Time ntime = new Time ( ); ntime.SetTime ( 11, 34, 15 ); Console.Write ( “Use the Display method: “ ); ntime.DisplayTime ( ); Console.Write ( “Add 5 hours to the Time object:” );,45,例子2.7 Time类的扩展方法(续),Time timeAdded = ntime.AddHours ( 5 ); timeAdded.DisplayTime ( ); Console. Write ( “Add 15 hours to the Time object: ” ); ntime.AddHours ( 15 ). DisplayTime ( ); Console.Write ( “Use fully qualified extension - method name: ” ); TimeExtension.DisplayTime ( nTime ); ,46,例子2.7 程序代码 (续),static class TimeExtensions public static void DisplayTime ( this Time aTime ) Console.WriteLine ( aTime.ToString ( ) ); public static Time AddHours ( this Time aTime, int hours ) Time newTime = new Time ( ); newTime.Minute = aTime.Minute; newTime.Second = aTime.Second; newTime.Hour = ( aTime.Hours + hours ) % 24; return newTime.; ,47,例子2.7 程序运行结果,Use the Display method: 11:34:15 AM Add 5 hours to the Time object:4:34:15 PM Add 15 hours to the Time object: 2:34:15 AM Use fully qualified extension-method name: 11:34:15 AM,48,例子2.8 扩展方法的进一步应用,本例编写一个把字符串类型变量s通过调用一个转换方法ToInt,转换成数字的程序。 由于在字符串类型中没有这个方法,而字符串类型已经是系统直接定义好的,故采取扩展方法技术增加这个方法,使用起来就像ToInt方法是String类型的一个实例方法一样。例如: String s = “200”; int i = s.ToInt ( );,49,例子2.8 扩展方法的应用(续),但是,实例方法只能通过一个类的实例(对象)来调用,不能直接通过类名来调用。而静态方法则只能通过类名来调用。例如,String类型的ToUpper方法就是一个实例方法,只能在一个String类型的对象上被调用,如: string name = “Joe”; Console.WriteLine ( name.ToUpper ( ) );,50,例子2.8 扩展方法的应用实例,using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DemoExtensionMethods public static class EMClass public ststic int ToInt ( this string s ) return Int32.Parse ( s ); class Program static void Main ( string args ) string s = “200”; int i = s.ToInt ( ); /调用扩展方法,无需传递参数 Console.WriteLine ( i ); ,51,例子2.8的程序代码说明,本例代码首先定义了一个静态类EMClass,在类的内部定义了一个静态方法ToInt,注意该方法的定义参数有一个this关键字(扩展方法可以有多个参数,但是只有第一个参数能被this修饰,表示它代表要被扩展的类型,这里是String),该方法实现的逻辑是将字符串转换为整数;接下来在Main方法中生成一个字符串,在此实例对象上调用方法ToInt得到转换后的数字结果“200”并在屏幕上打印显示出来。,52,2.5 泛型,目前主流的编程语言中,大部分是强类型编程语言,即要求变量或对象必须有自己的类型,不同类型之间的转换还要遵守严格规则。强类型编程语言有助于编写更加安全的程序代码,但是其通用性方面还有欠缺。考虑下面求2个整数中的较小者: int Min ( int a, int b ) if ( a b ) return a; else return b; 根据上面的代码,对于每一种希望比较的参数类型,比如long、float、double等,就需要编写一个该类型版本的函数。这就增大了程序员的工作量,非常不方便,也容易出错。,53,泛型概述,泛型是用于处理算法、数据结构的一种编程方法。其目标是采用广泛适用和可交互性的形式来表示算法和数据结构,以使它们能够直接用于软件构造。泛型类、结构、接口、委托和方法可以根据它们存储和操作的数据的类型来进行参数化。泛型能在编译时提供强大的类型检查,减少数据类型之间的显示转换。泛型类和泛型方法同时具备可重用性、类型安全和效率高等特性,通常用在集合和在集合上运行的方法中。,54,问题的产生,我们编写一个具有通用性质的Min方法如下: Object Min ( Object a, Object b ) if ( a b ) return a; else return b; 期望用对象Object代替具体的数据类型当作占位符,对任何类型的两个对象Object都能找出比较小的数。但是由于比较操作符“”不是定义在Object类型上的操作符,因而该段代码无法执行。可以借助一个通用的IComparable接口来实现比较运算。故上述代码修改如下: IComparable Min ( IComparable a, IComparable b ) if ( a.CompareTo( b ) 0 ) return a; else return b; ,55,泛型的引入,适应通用类型对象的问题解决后,又产生了新的问题。即每次使用这段代码时,都必须进行类型转换。如下面的方法调用代码需要将方法的返回值转换为整数类型: int a = 3, b = 5; int c = ( int ) Min ( a, b ); 频繁的类型转换会消耗计算机资源,造成程序的执行效率下降。为了从根本上解决问题,C# 从2.0 版就提出了泛型(generics)的概念,用泛型改编上面的代码为: T Min ( T a, T b ) where T: IComparable /CompareTo方法是接口IComparable的方法 if ( a.CompareTo ( b ) 0 ) return a; else return b; ,56,例子中泛型的语句说明,上述代码中,T是一个类型参数,代表一种数据类型,在调用时由实际传递的参数类型决定,该类型将自动替换所有出现T的地方; Min ( T a, T b )表示关于类型T的方法,它接受两个类型为T的参数,即a和b,返回值类型为T; IComparable表示关于类型T的泛型IComparable接口,类型T需要实现IComparable接口。当使用这段代码时,不再需要使用前面提到的类型转换的语句。而是可以写成下面的简化形式的语句:,57,泛型语句的进一步简化,int a = 3, b = 5; int c = Min ( a, b ); 这样Min返回结果的类型转换消失了,该代码的运行速度更快。 另外,编译器还可以从传递的参数类型(a和b)推断出Min方法的泛型T类型,使前面的代码表现的更简洁如下: int a = 3, b = 5; int c = Min ( a, b );,58,例子2.9 使用泛型方法Min的完整代码,using System; using System.Text; using System.Collections.Generic; namespace Sample public class GenericTest static T Min ( T a, T b ) where T: IComparable /CompareTo方法是接口IComparable的方法 if ( a.CompareTo ( b ) 0 ) return a; else return b; public static void Main ( ) int a = 3, b = 5; /这里可以是float, double, char等各种类型 int c = Min ( a, b ); Console.WriteLine ( c ); ,59,2.6 lambda表达式,lambda表达式是Visual C# 2008新增的用于定义简单的匿名方法。 lambda表达式首先是个参数表,参数表后面是lambda运算符(=,读作“go to”)和一个表示方法体的表达式 public delegate bool NumberPredicate ( int No ); NumberPredicate evenPredicate = No = ( No % 2 = 0); 在lambda表达式No % 2 = 0中,用运算符%确定参数No值是不是偶数。表达式产生的真假值由lambda表达式隐式返回。 lambda表达式不用指定返回值,返回类型可以从返回值或代理的返回值推定。,60,C# Lambda表达式来源,Lambda实际上源远流长,现在使用的机器都是冯-诺依曼体系的,属于图灵机,在那之前还有一种称作演算的理论,但是图灵机由于先被实现出来,所以大行其道,演算后来成就了函数式编程语言特别是Lisp,在函数式编程语言里函数是第一等元素,函数的参数,函数的返回值都是函数,程序没有变量,函数嵌套函数。而且函数式编程语言一直存在于象牙塔中,在工业界没有流行。但近年来工业界比较喜欢“复古”风格,而函数式编程语言能解决一些命令式编程难以解决的问题(或者解决起来非常麻烦),所以也走上了历史舞台。C#要做到函数风格编程怎么办?靠原来的方法定义的方式肯定不行,2.0的匿名方法初步解决了这个问题,但还不够,3.0的Lambda终于很好的解决了,一个Lambda就是一个delegate,一个delegate指向一个方法,现在我们使用Lambda也能简单的将方法作为参数传递了,还可以层层嵌套,简化了编程。,61,Lambda表达式本质,lambda是一个匿名方法,其本质上是匿名方法在语法上的简化,匿名方法具备的特性, lambda表达式也同样具备。它可以包含表达式和语句,并且可用于创建委托或表达式树类型。 使用lambda表达式是在C# 2.0推出的匿名方法的特性基础上,将匿名方法的语法进一步简化。另外,lambda表达式还通过使用表达式树推迟代码的编译时间,使得代码可以在系统运行时动态编译,增加代码的灵活性。 lambda表达式主要用于代替匿名方法,以更简洁的方式向方法中加入一些短小的代码片段。,62,Lambda表达式对匿名方法的改进,先看一下匿名方法的使用。在.net 2.0中System.Collections.-Generic命名空间下List里有一些新增的方法。比如Find,若使用匿名方法可写为: books.Find (delegate ( Book book ) return book.Price book.Price 50 ); 该表达式可以阅读为:给你一本书,如果它的价格小于50则返回true。 将使用了Lambda表达式的程序集反编译后,我们发现它和匿名方法基本相同。Lambda的输入参数就对应着delegate括号里面的参数,由于Lambda表达式可以推断参数的类型,所以这里的参数类型无需声明。,63,Lambda表达式的几种类型,Lambda操作符后面紧跟着表达式或者是语句块(这点和匿名方法也不同,匿名方法只能使用语句块而不能使用表达式)。下面列出了常见的Lambda表达式类型,其中x的类型省略了,编译器可以根据上下文推断出来,后面跟着的是表达式 x = x+1 /后面跟着表达式 Deleage ( int x ) return x+1; /后面跟着语句块 x = return x+1; /后面跟着语句块 Delegate ( int x) return x+1; /输入参数也可以带类型 ( int x ) = x+1 /后面跟着表达式 Delegate ( int x ) return x+1; /可输入多个参数,逗号分隔 ( x, y ) = x+y /后面跟着表达式 Delegate ( int x, int y ) return x+y; /无参的也行 () = 1 /无参数,后跟表达式 Delegate ( ) return 1; ,64,Lambda表达式和语句,Lambda表达式的形式如下: ( input parameter ) = expression lambda使用lambda运算符=,运算符的左边是可选的输入参数,右边是表达式。该运算符与赋值运算符优先级相同,也是右结合运算符。 Lambda语句的形式如下: ( input parameter ) = statement; Lambda的语句与表达式基本一样,只是运算符“=”右面使用花括号包含的代码快。,65,例子2.10 创建lambda表达式,using System; namespace Demolambda class Program delegate string MyDelegate ( string t, string n ); static void Main ( string args ) MyDelegate dele = ( t, n ) = /定义lambda表达式 string.Format ( “0 1”, t, n ); Console.WriteLine ( “调用lambda表达式n”); Console.WriteLine ( dele ( “Doctor”, “John” ); Console.WriteLine ( dele ( “Sir”, “Tomso

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论