方法类型化-委托.ppt

上传人:小飞机 文档编号:6298440 上传时间:2023-10-15 格式:PPT 页数:25 大小:340.49KB
返回 下载 相关 举报
方法类型化-委托.ppt_第1页
第1页 / 共25页
方法类型化-委托.ppt_第2页
第2页 / 共25页
方法类型化-委托.ppt_第3页
第3页 / 共25页
方法类型化-委托.ppt_第4页
第4页 / 共25页
方法类型化-委托.ppt_第5页
第5页 / 共25页
点击查看更多>>
资源描述

《方法类型化-委托.ppt》由会员分享,可在线阅读,更多相关《方法类型化-委托.ppt(25页珍藏版)》请在三一办公上搜索。

1、第9章 方法类型化委托,9.1 委托9.2 事件9.3 小结,9.1 委托,在C、C+和Pascal中,如果把函数的指针(地址)作为参数传递给另一个函数,当该指针被用于调用它所指向的函数时,我们就可以称之为回调函数。回调函数是一种功能强大的编程特性,窗口过程、异步过程调用等都需要使用回调函数。但是,函数指针只是一个内存地址,该地址不带任何额外信息,例如函数期望收到的参数个数、参数类型、函数的返回值类型以及函数的调用约定等,所以函数指针是非类型安全的。因此,为了保证程序的安全性,Java不提供任何具有指针函数功能的结构,但是C#提供这种结构,这就是类型安全的委托。,9.1.1 委托概述,在C#中

2、,委托是一种特殊的对象类型(即一种特殊的类),其特殊之处在于之前定义的对象类型都可以包含数据,而委托包含的只是方法的地址。也可以说,委托是对一类方法(参数和返回值类型相似的方法)的类型。和类在使用前要进行实例化一样,委托在使用前也要进行实例化。但需要注意的是,在术语方面,类有两个不同的术语,“类”表示较广义的定义,“对象”表示类的实例。但委托只有一个术语,在创建委托的实例时,所创建的委托的实例也称为委托。,9.1.1 委托概述,(1)确定将要引用方法的签名,声明一个委托类型。一般语法形式如下:访问修饰符 delegate 返回值类型 委托类名(形参列表);例如下列代码:public deleg

3、ate void Del(string message);委托声明在形式上类似于方法的定义,但是没有方法体,在返回值类型前需要添加delegate关键字。委托声明中的返回值类型、形参类型和形参个数要与被引用的方法匹配(不必完全匹配,委托支持协变与逆变,后面章节将进行详细介绍)。委托的声明实际就是一个类的定义(该类实际定义的是一类方法,而且只有方法,没有数据),所以可以在定义类的任何位置定义委托。,9.1.1 委托概述,(2)实例化一个委托。一般语法形式如下:委托类名 委托名=new 委托类名(被引用的方法名);或者如下形式:委托类名 委托名=被引用的方法名;例如下列代码。Del handler

4、=new Del(DelegateMethod);或者如下形式。Del handler=DelegateMethod;第二种语法是第一种语法的缩写,是C#2.0以上版本才支持的语法形式。因为C#2.0支持委托推断,即允许直接为委托实例指派方法名,而不需要先使用委托对象对其进行包装。示例代码中的DelegateMehod是一个被引用的具体方法名,不带“()”。因为handler实际是一个对象,对其进行赋值只是将DelegateMethod的内存单元地址传入handler中。有关委托的本质可参见后续章节。,9.1.1 委托概述,(2)实例化一个委托。一般语法形式如下:委托类名 委托名=new 委托

5、类名(被引用的方法名);或者如下形式:委托类名 委托名=被引用的方法名;例如下列代码。Del handler=new Del(DelegateMethod);或者如下形式。Del handler=DelegateMethod;第二种语法是第一种语法的缩写,是C#2.0以上版本才支持的语法形式。因为C#2.0支持委托推断,即允许直接为委托实例指派方法名,而不需要先使用委托对象对其进行包装。示例代码中的DelegateMehod是一个被引用的具体方法名,不带“()”。因为handler实际是一个对象,对其进行赋值只是将DelegateMethod的内存单元地址传入handler中。有关委托的本质可

6、参见后续章节。,9.1.1 委托概述,(3)委托调用。委托调用的目的就是调用委托所封装的方法。委托最主要的用途是实现函数回调.,【例9-1】委托实现函数回调 public delegate void Del(string message);class Program public static void DelegateMethod(string message)System.Console.WriteLine(message);static void Main(string args)Del handler=DelegateMethod;handler(Hello World);/传入参数H

7、ello World,9.1.1 委托概述,【例9-2】委托实现函数传递 public delegate void Del(string message);class Program public static void DelegateMethod(string message)System.Console.WriteLine(message);public static void MethodWithCallback(int param1,int param2,Del callback)/Del类委托做参数 callback(The number is:+(param1+param2).T

8、oString();static void Main(string args)Del handler=DelegateMethod;MethodWithCallback(1,2,handler);/委托实现函数传递,9.1.1 委托概述,【例9-3】委托引用对象方法 public delegate void Del(string message);public class MethodClass public void Method(string message)/非静态方法Method System.Console.WriteLine(message);,9.1.1 委托概述,class P

9、rogram public static void MethodWithCallback(int param1,int param2,Del callback)callback(The number is:+(param1+param2).ToString();static void Main(string args)MethodClass obj=new MethodClass();/MethodClass类的实例obj Del point=obj.Method;/引用方法时一定要加上对象名 point(Hello World);MethodWithCallback(1,2,point);,

10、9.1.3 匿名方法,在2.0之前的C#版本中,声明委托的惟一方法就是使用命名方法,即要使用委托传递和回调一个方法,该方法必须是已经存在的。C#2.0引入了匿名方法,即允许委托可以只传递代码块,使代码块成为委托参数。,【例9-4】使用匿名方法。class program delegate void Message();delegate int AddOne(int v);static void Main(string args)int y=10;AddOne ao=delegate(int val)val+;return val;,9.1.3 匿名方法,Console.WriteLine(y=

11、0,y+=1,y,ao(y);Message ms=delegate()Console.WriteLine(Anonymous Method);ms();Console.ReadLine();,9.1.3 匿名方法,匿名方法可以带参数,也可以不带参数。当定义带有参数的匿名方法时,应在关键字delegage后面定义参数类型和名称。如同一个常规方法,方法签名必须与它指派的委托的定义相匹配。当调用委托时,可以传递参数的值,与正常的委托调用完全相同。当定义不带参数的匿名方法时,可以在关键字deletgate后面添加一对空括号。如果委托类型的返回值类型为void,则匿名方法不能有返回值;否则,匿名方法的

12、返回值必须和委托类型的返回值兼容。对于上述示例代码中定义的两个匿名方法,返回值的类型分别为void和string。与普通的方法定义不同,匿名方法定义结束时,不能省略“;”。,9.1.3 匿名方法,编译器生成的匿名方法在类中是private可见性的,这会禁止未在类型内部定义的任何访问该方法。因为匿名方法是私有的,所以匿名方法中不能使用跳转语句(goto、break或者continue)从代码块内跳转到代码块外部。同样,代码块外部的跳转语句也不能跳转到代码块内部。匿名方法内部不能访问不安全的代码。不能访问在匿名方法外部的ref参数和out参数,但是可以使用匿名方法访问外部定义的其他变量。is运算符

13、的左侧不允许使用匿名方法。,9.1.4 创建多播委托,前面介绍的委托,包括匿名方法,都是单链的,即一个委托对象只能对应一个回调方法。若要通过委托同时调用多个方法,即使这些方法的签名都相同,也需要分别定义对应的委托对象,然后显式调用这些委托对象。事实上,C#提供了更简捷的方式实现多个方法的同时调用,这种委托就是多播委托(也称作多路委托、多路广播或者委托链)。我们可以使用加法运算符(+)或者加法赋值运算符(+=)向委托的方法列表中添加额外的方法,也可以使用减法运算符(-)或者减法赋值运算符(-=)从委托的方法链表中减少方法。,【例9-5】多播委托 class MyClass public void

14、 WordHello(string s)System.Console.WriteLine(Hello,0,s);public void WordGoodmorning(string s)System.Console.WriteLine(GoodMorning,0,s);public void WordGoodafternoon(string s)System.Console.WriteLine(Goodafternoon,0!,s);,9.1.4 创建多播委托,class Test public delegate void MyDelegate(string s);static void Ma

15、in(String args)MyClass MyObj=new MyClass();MyDelegate a,b,c,d,e;/定义了5个MyDelegate类型的委托对象 a=MyObj.WordHello;b=MyObj.WordGoodmorning;c=MyObj.WordGoodafternoon;d=a+b;/将a、b合并成d c+=d;/将d、c合并成新的c d(A);c(B);e=c-a;/将a从c中删除,e将只包含b和d e(C);Console.ReadLine();,9.1.4 创建多播委托,关于多播委托,需要注意如下事项。多播委托的签名需要统一返回void类型,否则只

16、能得到委托调用的最后一个方法的结果。多播委托的调用方法链顺序并未被正式定义,因此需要避免编写依赖于特定顺序调用方法的代码。多播委托包含一个逐个调用的委托集合,如果调用的方法抛出了异常,整个迭代就会停止。,9.1.4 创建多播委托,9.1.6 手工迭代,前面已经介绍了多播委托的创建和原理。通过创建委托链,能够实现对多个方法的调用。因为委托类型中的Invoke方法可以实现对_invocationList指向的数组的遍历。但是,通过分析Invoke的伪代码可以发现,它使用的是一个非常简单的算法,尽管该算法足以应付大部分情况,但是它也有很大的局限性,表现在如下两个方面。只能支持void返回值类型签名,

17、否则只能返回最后一个被调用方法的返回值。如果某个被调用的方法抛出异常,后面的其他方法就不会再被调用。显然,这两点便显现出了多播委托的不可靠性。为此,MultcastDelegate类提供了一个实例方法GetInvocationList,它用于显式调用链中的每一个委托,并使用符合需求的任意算法。,【例9-6】手工迭代。internal sealed class Light public String SwitchPosition()return The Light is off;internal sealed class Fan public String Speed()throw new In

18、validOperationException(The fan broke due to overheating);internal sealed class Speaker public String Volume()return The volume is loud;,9.1.6 手工迭代,public sealed class program private delegate String GetStatus();/声明一个委托 public static void Main()GetStatus getStatus=null;getStatus+=new GetStatus(new L

19、ight().SwitchPosition);getStatus+=new GetStatus(new Fan().Speed);getStatus+=new GetStatus(new Speaker().Volume);Console.WriteLine(GetComponentStatusReport(getStatus);private static String GetComponentStatusReport(GetStatus status)if(status=null)return null;StringBuilder report=new StringBuilder();De

20、legate arrayOfDelegates=status.GetInvocationList();foreach(GetStatus getStatus in arrayOfDelegates)try report.AppendFormat(011,getStatus(),Environment.NewLine);catch(Exception e)object component=getStatus.Target;report.AppendFormat(Failed to get status from 120Error:300,Environment.NewLine,(componen

21、t=null)?:component.GetType()+.),e.Message);return report.ToString();,9.1.6 手工迭代,1返回类型协变public class DelegateReturn public class DelegateReturn2:DelegateReturn public delegate DelegateReturn MyDelegate();class Program static void Main()MyDelegate myDelegate=Method;myDelegate();static DelegateReturn2

22、Method()DelegateReturn2 result=new DelegateReturn2();return result;,9.1.7 协变和抗变,2参数类型抗变public class DelegateParam public class DelegateParam2:DelegateParam public delegate void MyDelegate(DelegateParam2 param2);class Program static void Main()MyDelegate myDelegate=Method;DelegateParam2 param2=new De

23、legateParam2();myDelegate(param2);static void Method(DelegateParam param),9.1.7 协变和抗变,9.2 事件,事件是C#中一个比较高级的概念,定义了事件成员的类型,允许类型(或者类型的实例)在某些特定事情发生时通知其他对象。在整个.NET中所定义的事件都是基于委托的。某种意义上讲,事件就是委托的一种特殊形式。事件通常包括引发事件的发送方以及捕获事件并做出响应的接收方。在事件通信中,事件发送方无法确定哪个对象或方法将接收到(处理)它引发的事件,所需要的就是在发送方和接收方之间用一个纽带来联系。在C#中,使用委托作为该纽带

24、。事件的应用极为广泛,尤其是在窗体应用程序中,几乎所有的交互都是通过事件来实现的,例如在登陆窗口中单击登陆按钮,就是通过在按钮的事件中编写校验用户名和密码的语句来实现的。,9.3 小结,C#的委托类似于函数指针,但是比函数指针的安全性更高,且函数指针只能引用静态方法,而委托既能引用静态方法,也能引用实例方法。通过使用多播委托或者手工迭代,还可以实现多个方法的回调。事件是C#中的另一个重要概念,事件与处理方法之间的桥梁就是委托,事件发生了,委托就会知道,然后将事件传递给接收方,接收方通过处理方法进行相应的处理。委托和事件的联系非常紧密,主要针对高级应用,在理解上可能会有一定的难度。读者可以先了解它的作用和使用方法,其次研究其实现原理。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号