委托实现了类型安全的回掉方法,在.NET中回调无处不在,所以委托也无处不在,事件模型建立在委托机制上,本文将完成一次关于委托的旅行,全面阐述委托及其核心话题,逐一梳理委托、委托链、事件等。
关于委托
了解委托先从其定义开始,通常一个委托被声明为:
关键字delegate用于声明一个委托类型CalculateDelegate,可以对其添加访问修饰符,默认其返回类型为void,接受两个int类型的参数x和y,但是委托并不等于方法,而是一种引用类型,类似c++中的函数指针,指向一个方法。
下面的示例将介绍如何通过委托来实现一个计算器模拟程序,在基础上来了解关于委托的定义、创建和应用:
上述示例中,在DelegateDemo类中声明了一个CalculateDelegate的委托类型,它具有和绑定方法Add完全相同的返回类型和参数,否则无法通过编译,将方法传给CalculateDelegate的构造器,也就是将方法指派给委托CalculateDelegate委托,并将该引用赋给myDelegate变量,也就表示myDelegate变量保存指向了Add方法的引用,以此实现对Add的回调。
由此可见,委托表示了对其回调方法的签名,可以将方法当作参数来传递,并根据传入的方法来动态的调用方法,所以,只要提供和委托具有相同签名的方法就可以与委托绑定,例如:
同样可以将Sub分配给委托,如下:
多播委托委托链
在上述委托的实现中,Add方法和Sub方法可以绑定到同一个类型的委托上,那么它们可不可以绑定到同一个委托变量上呢?答案是可以,多个方法可以绑定到同一个委托变王小豆量上,在委托变量做回调的时候可以依次执行其绑定的方法,这种技术称为多播委托。在.NET中提供了相当简洁的语法类创建委托链,以+=和-=操作符来分别进行绑定和解除绑定操作,多个方法绑定到同一个委托变量就形成了一条委托链,对其调用时会以此调用所有绑定的回调方法。例如:
计算结果为 :210 112
再以-=来解除绑定
计算结果为:310,可见通过-=操作,解除了Sub方法。
事实上+=和-=操作分别调用了Delegate.Combine和Delegate.Remove方法,委托本质上仍然是一个类,如此简洁的语法正式因为CLR和编译在后台完成了一系列操作。
.NET的事件模型建立在委托的机制上,可以说事件是对委托的封装,从委托的示例中可知,在客户端可以随意对委托进行操作,一定程度上破化了面向对象的封装机制,因此事件实现了对委托的封装。
下面通过将委托的示例进行改造,来完成一个事件的定义过程:
示例中,对计算器模拟程序做了简要修改,从二者的对比中可以体会出事件的完整定义过程,主要包括:
-
王小豆
- 定义一个内部事件参数类型,用于存放事件引发时向事件处理程序传递的状态信息,EventArgs是事件数据类的基类。
- 声明事件委托,主要包括两个参数:一个表示事件的发送者对象,一个表示时间参数类对象。
- 定
义事件成员。 - 定义负责通知事件引发的方法,它被实现为Protected virtual方法,目的是可以在派生类中覆写该方法来拒绝监听事件。
- 定义一个触发事件的犯法,例如Calculate被调用时,表示有新的计算发生。
一个事件的完整程序就这样定义好了,然后还需要定义一个事件触发程序用来监听事件:
最后,在客户端 实现事件处理程序:
如果对设计模式有所了解,上述实现过程实质是观察者模式在委托中的应用。