收藏 分享(赏)

代理(delegate).doc

上传人:hskm5268 文档编号:7875482 上传时间:2019-05-28 格式:DOC 页数:12 大小:35.15KB
下载 相关 举报
代理(delegate).doc_第1页
第1页 / 共12页
代理(delegate).doc_第2页
第2页 / 共12页
代理(delegate).doc_第3页
第3页 / 共12页
代理(delegate).doc_第4页
第4页 / 共12页
代理(delegate).doc_第5页
第5页 / 共12页
点击查看更多>>
资源描述

1、有些书上也称“代表”或“委托”。C#中取消了指针的概念。对指针恋恋不舍的程序员可以有两种解决方法:声明“非安全”(unsafe)代码段然后在其中使用指针或者使用 C的一个引用类型“代理”(delegate )。“代理”相当与 C 中的函数指针原型,区别是 C是类型安全的。“代理”(delegate )(代表、委托):“代理”是类型安全的并且完全面向对象的。(1)在 C中,所有的代理都是从 System.Delegate 类派生的(delegate 是System.Delegate 的别名)。(2)代理隐含具有 sealed 属性,即不能用来派生新的类型。(3)代理最大的作用就是为类的事件绑定事

2、件处理程序。(4)在通过代理调用函数前,必须先检查代理是否为空(null),若非空,才能调用函数。(5)在代理实例中可以封装静态的方法也可以封装实例方法。(6)在创建代理实例时,需要传递将要映射的方法或其他代理实例以指明代理将要封装的函数原型(.NET 中称为方法签名: signature)。注意,如果映射的是静态方法,传递的参数应该是类名. 方法名,如果映射的是实例方法,传递的参数应该是实例名. 方法名。(7)只有当两个代理实例所映射的方法以及该方法所属的对象都相同时,才认为它们是想等的(从函数地址考虑)。(8)多个代理实例可以形成一个代理链,System.Delegate 中定义了用来维护

3、代理链的静态方法 Combion,Remove,分别向代理链中添加代理实例和删除代理实例。(9)代理的定义必须放在任何类的外面,如 delegate int MyDelegate();而在类的方法中调用 MyDelegate d = new MyDelegate(MyClass.MyMethod);来实例化自定义代理的实例。(10)代理三步曲:a生成自定义代理类:delegate int MyDelegate();b然后实例化代理类:MyDelegate d = new MyDelegate(MyClass.MyMethod);c最后通过实例对象调用方法:int ret = d();资料引用:

4、http:/ / c 中的函数指针,可能更好理解#include “stdafx.h“#include “stdio.h“#include “stdlib.h“int (* Test) (int l); /定义函数指针/以下定义了两个处理函数,程序会根据情况调用不同的过程int Add(int t)return t+ t;int Mut(int t)return t*t;/把函数做参数int test2(int t,int (* p) (int )return p(t);int main(int argc, char* argv)char input8;printf(“Please Input

5、 a Number!n“);scanf(“%s“,input);int t = atoi(input);int p;/大于 10,此指针指向 Add()if(t 10)Test = Add;/小于 10,此指针指向 Mut()elseTest = Mut;/通过指针调用p = Test(t);printf(“The Result is %d“,p);if(t 10)p = test2(t,Add);/小于 10,此指针指向 Mut()elsep = test2(t,Mut);return 0;/ c# 中的代理 ,和函数指针其实一样,不过扩展了一些功能而已 :)using System;nam

6、espace tdele/ / Class2 的摘要说明。/ public class Class2public delegate int Test(int t); /申明一个代理(函数指针 )public event Test e; / 触发词函数的事件/以下定义了两个处理函数,程序会根据情况调用不同的过程public int Add(int t)return t + t;public int Mut(int t)return t * t;public Class2()/ TODO: 在此处添加构造函数逻辑/public void test()int t = Int32.Parse(Cons

7、ole.ReadLine();/大于 10,事件 e 的处理函数用 Add()if(t 10)this.e += new Test(Add);/小于 10,Mut()elsethis.e += new Test(Mut);/引发一个事件,得到处理结果int p = e(t);/打印输出Console.Write(“The Result is 0“,p);if(t 10)p = test(t,new Test(Add);/小于 10,Mut()elsep = test(t,new Test(Mut);/打印输出Console.Write(“The Result is 0“,p);public i

8、nt test(int i,Test p)return p(i); public static void Main()Class2 t = new Class2();t.test();C#中的“代理 ”和“事件” 事件(event)是一个非常重要的概念,我们的程序时刻都在触发和接收着各种事件:鼠标点击事件,键盘事件,以及处理操作系统的各种事件。所谓事件就是由某个对象发出的消息。比如用户按下了某个按钮,某个文件发生了改变,socket 上有数据到达。触发事件的对象称作发送者(sender),捕获事件并且做出响应的对象称作接收者(receiver),一个事件可以存在多个接受者。 在异步机制中,事件

9、是线程之间进行通信的一个非常常用的方式。比如:用户在界面上按下一个按钮,执行某项耗时的任务。程序此时启动一个线程来处理这个任务,用户界面上显示一个进度条指示用户任务执行的状态。这个功能就可以使用事件来进行处理。可以将处理任务的类作为消息的发送者,任务开始时,发出“TaskStart”事件,任务进行中的不同时刻发出“TaskDoing” 事件,并且携带参数说明任务进行的比例,任务结束的时候发出“TaskDone”事件,在画面中接收并且处理这些事件。这样实现了功能,并且界面和后台执行任务的模块耦合程度也是最低的。 具体说 C#语言,事件的实现依赖于“代理” (delegate )的概念,先了解一下

10、代理。 代理(delegate) delegate 是 C#中的一种类型,它实际上是一个能够持有对某个方法的引用的类。与其它的类不同,delegate 类能够拥有一个签名(signature),并且它只能持有与它的签名相匹配的方法的引用。它所实现的功能与 C/C+中的函数指针十分相似。它允许你传递一个类 A 的方法 m 给另一个类 B 的对象,使得类 B 的对象能够调用这个方法 m。但与函数指针相比, delegate 有许多函数指针不具备的优点。首先,函数指针只能指向静态函数,而 delegate 既可以引用静态函数,又可以引用非静态成员函数。在引用非静态成员函数时,delegate 不但保

11、存了对此函数入口指针的引用,而且还保存了调用此函数的类实例的引用。其次,与函数指针相比,delegate 是面向对象、类型安全、可靠的受控(managed)对象。也就是说,runtime 能够保证 delegate指向一个有效的方法,你无须担心 delegate 会指向无效地址或者越界地址。 实现一个 delegate 是很简单的,通过以下 3 个步骤即可实现一个 delegate: 1 声明一个 delegate 对象,它应当与你想要传递的方法具有相同的参数和返回值类型。 2 创建 delegate 对象,并将你想要传递的函数作为参数传入。 3 在要实现异步调用的地方,通过上一步创建的对象来

12、调用方法。 下面是一个简单的例子: public class MyDelegateTest / 步骤 1,声明 delegate 对象 public delegate void MyDelegate(string name); / 这是我们欲传递的方法,它与 MyDelegate 具有相同的参数和返回值类型 public static void MyDelegateFunc(string name) Console.WriteLine(“Hello, 0“, name); public static void Main () / 步骤 2,创建 delegate 对象 MyDelegate m

13、d = new MyDelegate(MyDelegateTest.MyDelegateFunc); / 步骤 3,调用 delegate md(“sam1111“); 输出结果是:Hello, sam1111 下面我们来看看事件是如何处理的: 事件(event ) C#中的事件处理实际上是一种具有特殊签名的 delegate,象下面这个样子: public delegate void MyEventHandler(object sender, MyEventArgs e); 其中的两个参数,sender 代表事件发送者,e 是事件参数类。MyEventArg 类用来包含与事件相关的数据,所有

14、的事件参数类都必须从 System.EventArgs 类派生。当然,如果你的事件不含特别的参数,那么可以直接用 System.EventArgs 类作为参数。结合 delegate 的实现,我们可以将自定义事件的实现归结为以下几步: 1:定义对象类型,它有两个参数,第一个参数是事件发送者对象,第二个参数是事件参数类对象。 2:定义事件参数类,此类应当从 System.EventArgs 类派生。如果事件不带参数,这一步可以省略。 3:定义事件处理方法,它应当与 delegate 对象具有相同的参数和返回值类型。 4:用 event 关键字定义事件对象,它同时也是一个 delegate 对象。

15、 5:用+=操作符添加事件到事件队列中( -=操作符能够将事件从队列中删除)。 6:在需要触发事件的地方用调用 delegate 的方式写事件触发方法。一般来说,此方法应为 protected 访问限制,既不能以 public 方式调用,但可以被子类继承。名字是可以是 OnEventName 7:在适当的地方调用事件触发方法触发事件。 下面是一个例子,例子模仿容器和控件的模式,由控件触发一个事件,在容器中捕捉并且进行处理。 事件的触发者: / / 事件的触发者 / public class Control public delegate void SomeHandler(object send

16、er, System.EventArgs e); /* * 可以采用系统提供的 System.EventHandler, 这里为了说明情况使用了自己定义的 delegate * 如果需要在事件的参数中使用自己定义的类型,也要自己定义 delegate */ /public event System.EventHandler SomeEvent; public event SomeHandler SomeEvent; public Control() /这里使用的 delegate 必须与事件中声名的一致 /this.SomeEvent += new System.EventHandler(th

17、is.Control_SomeEvent); this.SomeEvent += new SomeHandler(this.ProcessSomeEvent); public void RaiseSomeEvent() EventArgs e = new EventArgs(); Console.Write(“Please input a:“); string s = Console.ReadLine(); /在用户输入一个小 a 的情况下触发事件,否则不触发 if (s = “a“) SomeEvent(this, e); /事件的触发者自己对事件进行处理,这个方法的参数必须和代理中声名的一

18、致 private void ProcessSomeEvent(object sender, EventArgs e) Console.WriteLine(“hello“); 事件的接收者: / / 事件的接收和处理者 / class Container private Control ctrl = new Control(); public Container() /这里使用的 delegate 必须与事件中声名的一致 /ctrl.SomeEvent += new EventHandler(this.OnSomeEvent); ctrl.SomeEvent += new Control.So

19、meHandler(this.ResponseSomeEvent); ctrl.RaiseSomeEvent(); public static void Main() Container pane = new Container(); /这个 readline 是暂停程序用的,否则画面会一闪而过什么也看不见 Console.ReadLine(); /这是事件的接受者对事件的响应 private void ResponseSomeEvent(object sender, EventArgs e) Console.WriteLine(“Some event occur!“); 程序运行的结果如下:

20、 please input a:a hello Some event occur! 事件的应用 例如有下面的需求需要实现:程序主画面中弹出一个子窗口。此时主画面仍然可以接收用户的操作(子窗口是非模态的)。子窗口上进行某些操作,根据操作的结果要在主画面上显示不同的数据。我发现一些程序员这样实现这个功能: 主画面弹出子窗口后,将自己的指针交给子画面,然后在子画面中使用这个指针,调用主画面提供的方法,改变主画面上的数据显示。这样虽然可以达到目的,但是各个模块之间产生了很强的耦合。一般说来模块之间的调用应该是单方向的:模块 A 调用了模块 B,模块 B 就不应该反向调用 A,否则就破坏了程序的层次,加强了耦合程度,也使得功能的改变和追加变得很困难。 这时正确的做法应该是在子窗口的操作过程中发出各种事件,而由主窗口捕捉这些事件进行处理,各个模块专心的做自己的事情,不需要过问其他模块的事情。参考文献 sam111 的 blog:http:/ C#中的 delegate 和 event

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

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报