事件和委托

事件和委托 事件是对象发送的消息,以发信号通知操作的发生。操作可能是由用户交互(例如鼠标单击)引起的,也可能是由某些其他的程序逻辑触发的。引发事件的对象称为事件发送方。捕获事件并对其作出响应的对象叫做事件接收方。 在事件通信中,事件发送方类不知道哪个对象或方法将接收到(处理)它引发的事件。所需要的是在源和接收方之间存在一个媒介(或类似指针的机制)。.NET Framework 定义了一个特殊的类型 (Delegate),该类型提供函数指针的功能。 委托是可保存对方法的引用的类。与其他的类不同,委托类具有一个签名,并且它只能对与其签名匹配的方法进行引用。这样,委托就等效于一个类型安全函数指针或一个回调。虽然委托具有许多其他的用途,但这里只讨论委托的事件处理功能。一个委托声明足以定义一个委托类。声明提供委托的签名,公共语言运行库提供实现。下面的示例显示了事件委托声明。 public class WakeMeUp { // AlarmRang has the same signature as AlarmEventHandler. public void AlarmRang(object sender, AlarmEventArgs e) {…}; … } 只有当事件生成事件数据时才需要自定义事件委托。许多事件,包括一些用户界面事件(例如鼠标单击)在内,都不生成事件数据。在这种情况下,类库中为无数据事件提供的事件委托 System.EventHandler 便足够了。其声明如下。 delegate void EventHandler(object sender, EventArgs e); 事件委托是多路广播的,这意味着它们可以对多个事件处理方法进行引用。有关详细信息,请参见 Delegate。委托考虑了事件处理中的灵活性和精确控制。通过维护事件的已注册事件处理程序列表,委托为引发事件的类担当事件发送器的角色。 如何:将事件处理程序方法连接到事件 若要使用在另一个类中定义的事件,必须定义和注册一个事件处理程序。事件处理程序必须具有与为事件声明的委托相同的方法签名。通过向事件添加事件处理程序可注册该处理程序。向事件添加事件处理程序后,每当该类引发该事件时都会调用该方法。 有关阐释引发和处理事件的完整示例,请参见如何:引发和使用事件。 为事件添加事件处理程序方法 定义一个具有与事件委托相同的签名的事件处理程序方法。 public class WakeMeUp { // AlarmRang has the same signature as… Continue reading 事件和委托

C#委托和事件(Delegate、Event、EventHandler、EventArgs)

14.1、委托 当要把方法作为实参传送给其他方法的形参时,形参需要使用委托。委托是一个类型,是一个函数指针类型,这个类型将该委托的实例化对象所能指向的函数的细节封装起来了,即规定了所能指向的函数的签名,也就是限制了所能指向的函数的参数和返回值。当实例化委托的时候,委托对象会指向某一个匹配的函数,实质就是将函数的地址赋值给了该委托的对象,然后就可以通过该委托对象来调用所指向的函数了。利用委托,程序员可以在委托对象中封装一个方法的引用,然后委托对象作为形参将被传给调用了被引用方法的代码,而不需要知道在编译时刻具体是哪个方法被调用。 一般的调用函数,我们都不会去使用委托,因为如果只是单纯的调用函数,使用委托更麻烦一些;但是如果想将函数作为实参,传递给某个函数的形参,那么形参就一定要使用委托来接收实参,一般使用方法是:在函数外面定义委托对象,并指向某个函数,再将这个对象赋值给函数的形参,形参也是该委托类型的对象变量,函数里面再通过形参来调用所指向的函数。 14.1.1、定义委托 语法如下: delegate result-type Identifier ([parameters]); 说明: result-type:返回值的类型,和方法的返回值类型一致 Identifier:委托的名称 parameters:参数,要引用的方法带的参数 小结: 当定义了委托之后,该委托的对象一定可以而且也只能指向该委托所限制的函数。即参数的个数、类型、顺序都要匹配,返回值的类型也要匹配。 因为定义委托相当于是定义一个新类,所以可以在定义类的任何地方定义委托,既可以在一个类的内部定义,那么此时就要通过该类的类名来调用这个委托(委托必须是public、internal),也可以在任何类的外部定义,那么此时在命名空间中与类的级别是一样的。根据定义的可见性,可以在委托定义上添加一般的访问修饰符:当委托定义在类的外面,那么可以加上public、internal修饰符;如果委托定义到类的内部,那么可以加上public、 private、 protected、internal。一般委托都是定义在类的外面的。 14.1.2、实例化委托 Identifier objectName = new Identifier( functionName ) 实例化委托的实质就是将某个函数的地址赋值给委托对象。在这里: Identifier :这个是委托名字。 objectName :委托的实例化对象。 functionName:是该委托对象所指向的函数的名字。对于这个函数名要特别注意:定义这个委托对象肯定是在类中定义的,那么如果所指向的函数也在该类中,不管该函数是静态还是非静态的,那么就直接写函数名字就可以了;如果函数是在别的类里面定义的public、internal,但是如果是静态,那么就直接用类名.函数名,如果是非静态的,那么就类的对象名.函数名,这个函数名与该对象是有关系的,比如如果函数中出现了this,表示的就是对当前对象的调用。 14.1.3、委托推断 C# 2.0用委托推断扩展了委托的语法。当我们需要定义委托对象并实例化委托的时候,就可以只传送函数的名称,即函数的地址: Identifier objectName = functionName; 这里面的functionName与14.1.2节中实例化委托的functionName是一样的,没什么区别,满足上面的规则。 C#编译器创建的代码是一样的。编译器会用objectName检测需要的委托类型,因此会创建Identifier委托类型的一个实例,用functionName即方法的地址传送给Identifier的构造函数。 注意: 不能在functionName后面加括号和实参,然后把它传送给委托变量。调用方法一般会返回一个不能赋予委托变量的普通对象,除非这个方法返回的是一个匹配的委托对象。总之:只能把相匹配的方法的地址赋予委托变量。 委托推断可以在需要委托实例化的任何地方使用,就跟定义普通的委托对象是一样的。委托推断也可以用于事件,因为事件基于委托(参见本章后面的内容)。 14.1.4、匿名方法 到目前为止,要想使委托工作,方法必须已经存在。但实例化委托还有另外一种方式:即通过匿名方法。 用匿名方法定义委托的语法与前面的定义并没有区别。但在实例化委托时,就有区别了。下面是一个非常简单的控制台应用程序,说明了如何使用匿名方法: using System; namespace Wrox.ProCSharp.Delegates { class Program {… Continue reading C#委托和事件(Delegate、Event、EventHandler、EventArgs)