C#委托(delegate)与事件(event)
在C#中,委托(delegate)是一种引用类型,在其他语言中,与委托最接近的是函数指针,但委托不仅存储对方法入口点的引用,还存储对用于调用方法的对象实例的引用。简单的讲委托(delegate)是一种类型安全的函数指针.
仅仅看它的概念,可能还是很模糊,我们来举例子由浅入深地说明一下。(强烈提醒:注意代码中的一些关键注释。代码完全可以复制下来直接运行。)
需求:《收费系统》计费标准:会员1元/小时;临时用户:1.5元/小时。
//我们先来看看不使用委托,该如何实现
//运行结果: 您是临时用户,使用了3个小时,需要付费4.5元
您是会员,使用了3个小时,需要付费3元
//显然,尽管这样解决了问题,但我不说,大家也很容易想到,这个解决方案的可扩展性很差,如果日后我们需要再添加其他结账方式,就不得不反复修改枚举和Charging()方法,以适应新的需求。
//接下来用委托实现一把
//运行结果: 您是会员,使用了3个小时,需要付费3元
您是普通用户,使用了3个小时,需要付费4.5元
您是会员,使用了3个小时,需要付费3元
您是普通用户,使用了3个小时,需要付费4.5元
//这样,我们看到,利用委托屏蔽掉了switch语句。
小结:委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。
//虽然我们做到了可扩展,但是考虑到面向对象,要做到对象的封装,我们可以把上述代码做以下改进。
//运行结果:您是会员,使用了3个小时,需要付费3元
您是普通用户,使用了3个小时,需要付费4.5元
//这里有一条语句很奇怪(publicChargingDelegate delegate1;),并不是所有的字段都应该声明成public,合适的做法是应该public的时候public,应该private的时候private。
但是这里,我们不能改成private,因为声明委托的目的就是为了把它暴露在类的客户端进行方法的注册,你把它声明为private了,客户端对它根本就不可见。
不禁想到,如果delegate1不是一个委托类型,而是一个string或者int类型,我们会怎么做?自然是使用属性对字段进行封装了。
这个时候,我们就不得不用到事件!
我们再来优化代码:
我们看到,在客户端中,使用 “=”赋值语法(直接访问)会报错,只能放在+=或-=的右边。说明 MakeCharge被声明为私有的了。
难道事件仅仅是为了使共有变私有嘛?当然不是,详见以下实例。
需求:《收费系统》上机卡充值,在数据库中,一方面更改该卡的余额,另一方面储存充值记录。
代码实现:
注:这里我们用到了一种重要的设计模式,即:观察者模式.可以认为是先有观察者模式,才有的委托事件技术.观察者设计模式是为了定义对象间的一种一对多的依赖关系,以便于当一个对象的状态改变时,其他依赖于它的对象会被自动告知并更新。它是一种松耦合的设计模式。
综上,我们由浅到深得研究了委托与事件。以下总结了几点,需要大家注意:
1、委托是一种引用方法的类型,一旦为委托分配了方法,委托将于该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的“类”,委托的实例将代表一个具体的函数。
2、委托也可以看成是一种数据类型,可以用于定义量,但它是一种特殊的数据类型,它可以接受的数值只能是一个函数,更确切的说,委托的变量可以接受一个函数的地址。
3、一个委托可以搭载多个方法,所有方法被依次唤起,更重要的是,它可以使委托对象所搭载的方法并不一定属于同一个类。
4、委托对象所搭载的方法必须具有相同的参数列表和返回值类型。