第四讲 委托与事件 PowerPoint 演示文档_第1页
第四讲 委托与事件 PowerPoint 演示文档_第2页
第四讲 委托与事件 PowerPoint 演示文档_第3页
第四讲 委托与事件 PowerPoint 演示文档_第4页
第四讲 委托与事件 PowerPoint 演示文档_第5页
已阅读5页,还剩30页未读 继续免费阅读

下载本文档

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

文档简介

1、C#.NET编程技术第四讲 委托与事件内容提要n“方法”或“函数”的实质nC#委托n多播委托nC#事件机制“方法”“函数”的实质n函数是什么?一个函数体,实质上是内存中的一段区域n代码段,.text节变量也是内存中的一段区域n堆、栈函数体所在的内存区域保存的是可执行代码变量所在的内存区域保存的是数据函数体就是一段内存区域n对函数的调用,实质上是跳到该内存区域去执行指令当然,还伴随现场保护、参数压栈等行为00402384 push ebp00402385 mov ebp,esp00402387 push 0FFh00402389 push 4070B8h0040238E push 40384Ch

2、00402393 mov eax,fs:0000000000402399 push eax0040239A mov dword ptr fs:0,esp004023A1 ret. .0040B000 call 00402384系统内存C+的函数指针int DoSomething(int iPara1, int iPara2) return 0;typedef int (* FunctionPointer)(int, int);FunctionPointer bc = &DoSomething;bc(1, 2);00405810 push ebp. .00405828 xor eax,e

3、ax.00405830 ret004016B8 mov dword ptr ebp-4,offset ILT+300(DoSomething)004016BF mov esi,esp004016C1 push 2004016C3 push 1004016C5 call dword ptr ebp-4函数指针中存放的,就是函数体起始地址C+回调函数n调用一个函数a时,将指向函数b的指针当作参数传给函数a函数a在内部可以调用函数b,并将某些信息传递出来/ 来自platform SDKBOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam );

4、typedef BOOL (CALLBACK *WNDENUMPROC)(HWND hwnd, LPARAM lParam ); C#不允许使用指针n确切的说,是安全代码不能使用指针使用C#编程除非极特殊的需要,都应该使用安全代码n如果实现“回调函数”的功能?不能在使用函数指针C#委托C#委托n目标:把一个方法传递给别人,供其调用C+用函数指针来传递n方式:将函数名放进一个容器送过去“函数名”实质上是对函数体所在内存单元的一个引用这个“容器”要定义一些规则,说明什么样函数才可放进来定义委托n说明容器的规则:什么样的函数能放进来n以上语句定义了一个名为GetStringDelegate的委托类型

5、说明接收一个int参数,返回string参数的函数可以放进来public delegate string GetStringDelegate(int seed);使用委托n将函数放进“容器”委托类型实例public delegate string GetStringDelegate(int seed);class Program static void Main(string args) GetStringDelegate d; d = new GetStringDelegate(GetString); d(18); static string GetString(int seed) retu

6、rn ; 定义委托声明委托实例将一个函数放入委托调用放入委托的函数可放入委托的函数n符合委托给出的参数、返回值定义的函数这种参数、返回值的定义,叫做“函数的签名”n能看见的函数都可以放静态的,实例化的public的,private的(只要能访问到)匿名函数n委托是个容器,里面装着函数(方法)装入委托的函数,一定是已经定义的吗?n匿名委托往委托实例里装一个现写的函数这个函数不需要名字,只有函数体匿名函数public delegate string GetStringDelegate(int seed);class Program static void Main(string args) Get

7、StringDelegate d = delegate(int seed) return “”; d(18); 使用匿名方法建立委托的好处n代码简洁:不用的时候不定义函数n外部定义的局部变量可以直接使用 void MyFunction() int outerPara = 2; GetStringDelegate GetString = delegate(int seed) int innerPara = outerPara; return ; ; 外部的out/ref参数不能引用! void MyFunction(out int para) GetStringDelegate GetStrin

8、g = delegate() para = 1; return ; ; void MyFunction(ref int para) GetStringDelegate GetString = delegate() para = 1; return ; ; 多播委托n一个委托只能装一个函数体么?可以装多个签名相同的函数体ndelegate关键字定义的委托,实质上是个派生类System.DelegateSystem.MulticastDelegatedelegate关键字定义的委托多播委托(续)n所有delegate关键字定义的委托类型,都派生自MulticastDelegate因此,也都具有多播

9、委托的能力多播委托:一个委托装了对多个函数体的引用n多播委托,调用所有函数n多播委托的返回类型必须是void为什么?public delegate void MyDelegate();class Programstatic void Func1() Console.WriteLine(“Func1 called.”); static void Func2() Console.WriteLine(“Func2 called.”); static void Func3() Console.WriteLine(“Func3 called.”); static void Main(string arg

10、s)MyDelegate myDelegate;myDelegate = new MyDelegate(Func1);myDelegate += new MyDelegate(Func2);myDelegate += new MyDelegate(Func3);myDelegate();多播委托实质上是委托列表public abstract class MulticastDelegate : Delegate / Fields private IntPtr _invocationCount; / 有多少个函数体引用private object _invocationList; / 多个Mult

11、icastDelegate实例 n只装入一个函数体引用(不使用这两个字段)_invocationCount = 0_invocationList = nulln装入多个函数体引用装入多个函数体引用_invocationCount = 函数体引用数量函数体引用数量_invocationList = MulticastDelegate as object使用多播委托的问题n调用函数链的顺序并未定义不一定按照源码中加入的顺序调用应避免依赖这个顺序的处理方式n一旦某个函数执行出现异常,所以未曾调用的函数不再被调用应避免函数中出现未捕获的异常多播委托的作用n执行一条语句(执行委托实例),可以做若干“事情

12、”装入一个函数体引用,就可以做一件“事情”n第三方往委托实例中加入函数引用可以让系统做第三方指定的“事情”public delegate void MyDelegate();public class MyClassprivate MyDelegate _action;public MyDelegate Action get return _action; public MyClass() _action = delegate() Console.WriteLine(“Inner called.”); public void DoSomething() _action(); MyClass my

13、ClassInstance = new MyClass();myClassInstance.Action += new MyDelegate(Func2);myClassInstance.Action += new MyDelegate(Func3);/ .myClassInstance. DoSomething();声明一个委托实例,作为类字段执行委托实例,即执行其中的所有函数往MyClass实例的_action字段增加两个函数引用C#事件nWindows是基于消息的操作系统应用程序与OS通过消息机制交互nC#类库使用“事件”封装了消息事实上,MFC、VB等,也是对消息封装从而形成事件C#的

14、事件机制应用程序WindowsWM_LBUTTONUPWM_LBUTTONDOWNbtnTest.WndProcbtnTest.WmMouseUpbtnTest.OnMouseClickbtnTest.MouseClick事件事件机制的本质是多播委托public delegate void EventHandler(object sender, EventArgs e);public class MyClasspublic EventHandler MyEvent;static void Main(string args) MyClass mc = new MyClass(); mc.MyEv

15、ent += new EventHandler(函数1); mc.MyEvent += new EventHandler(函数2); 定义一个委托声明一个委托实例作为类成员加入多个函数引用event关键字的作用n对于多播委托,“+=”操作符的默认行为当委托为null时,等同于”=”n将右边的委托实例赋与自身当委托不为null时,自身变为“+=”右的委托实例,其它委托实例在_invocationList中n这个默认行为无法更改n使用event关键字,可以自定义加入函数引用的行为使用event关键字自定义行为public event MyDelegate MyEvent add / 自定义+=行为

16、remove / 自定义-=行为默认时(无中的add、remove定义),若声明一个名为”MyEvent”的事件,则隐含表示声明了一个名为MyEvent的委托。+=、-=等行为都针对这个委托实施。通过add/remove,可自定义行为方式。例如System.Windows.Forms.Control就采用了集中管理的方法对待所有预定义事件System.Windows.Forms.Controlnpublic class Control : Component将所有事件对应的委托放在base.events中激发某个事件时,通过关键字在base.events队列里寻找对应的委托实例每个事件对应一个

17、委托实例base.events即Component类的events字段,类型为EventHandlerList,实质上是一个哈希表System.Windows.Forms.ControlSystem.Windows.Forms.Controlevent Clickevent DoubleClickevent KeyPress.keyobjectnextEventClickEventHandler委托实例EventDoubleClickEventHandler委托实例EventKeyPressKeyPressEventHandler委托实例public class Controlprivate

18、static readonly object EventClick;public event EventHandler Clickadd base.Events.AddHandler(EventClick, value); remove base.Events.RemoveHandler(EventClick, value); protected virtual void OnClick(EventArgs e)EventHandler handler = (EventHandler) base.EventsEventClick;if (handler != null) handler(this, e); 定义一个值,作为Click事件处理函数在列表中的key定义Click事件,使其”+=”操作为向events列表中增加委托实例,”-=”为删除这个函数触发Click事件。可以看到,其事件处理函数要到base.events队列中找事件处理函数和参数n返回值必须是void,对参数无要求void Func(.)n对于Control类及其派生类,一般性的事件处理委托如下:void EventHandler(object s, Event

温馨提示

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

评论

0/150

提交评论