这一篇,我们将来聊聊委托和事件的关系
首选我对于event这个关键字比较陌生,所以查了一下event的定义
事件(Event)基本上说是一个用户操作,比如按键、点击、鼠标移动等等,或者是一些出现,如系统生成的通知。应用程序需要在事件发生时响应时间。例如,中断。事件是用于进程间通信
那么他和委托有什么关系呢??我们继续“打招呼”的例子来学习通过事件来使用委托
我们将上一篇的基础代码进行部分的封装,改写为两个类,将GreetPeople和委托的声明放到一个名叫GreetingManager的类中,客户端提供了两种不同的调用,一种是普通的调用方法,第二种是多个方法绑定到同一个委托
namespace 委托DEMO
{
//定义委托,它定义了可以代表的方法的类型
public delegate void GreetingDelegate(string name);
class GreetingManager1
{
public void GreetPeople(string name,GreetingDelegate MakeGreeting)
{
MakeGreeting(name);
}
}
}
class Program
{
private static void EnglishGreeting(string name)
{
Console.WriteLine("Morning," + name);
}
private static void ChineseGreeting(string name)
{
Console.WriteLine("早上好呀," + name);
}
static void Main(string[] args)
{
GreetingManager1 gm = new GreetingManager1();
gm.GreetPeople("Celine", EnglishGreeting);
gm.GreetPeople("陈丹",ChineseGreeting);
Console.ReadKey();
//将多个方法绑定到一个委托上
GreetingManager1 gm2 = new GreetingManager1();
GreetingDelegate delegate2;
delegate2 = EnglishGreeting;
delegate2 += ChineseGreeting;
gm2.GreetPeople("陈丹",delegate2);
Console.ReadKey();
}
}
面向对象讲究的是封装,如果我们声明了一个Person类,封装了属性和方法,那么类比这个例子,我们是否也可以在GreetingManager类的内部声明delegate这个变量?那样就可以在类的内部直接使用了,于是我们将这个类改写为:
public class GreetingManager
{
//在类的内部声明delegate变量
public GreetingDelegate delegate1;
public void GreetPeople(string name, GreetingDelegate MakeGreeting)
{
MakeGreeting(name);
}
}
static void Main(string[] args)
{
GreetingManager gm = new GreetingManager();
//第一个“=”是赋值,第二个"+="是方法绑定,一致性?
gm.delegate1 = EnglishGreeting;
gm.delegate1 += ChineseGreeting;
gm.GreetPeople("CELINE");
}
虽然看似进行了封装,但是这个封装还是存在着问题的,想想我们的机房的实体类
我们使用了property对内部private的变量进行访问控制,来达到封装的效果,我们不能在类的范围以外直接访问这些域(field),但是我们可以拥有访问这些私有域的属性。
再来看我们的委托变量,直接把字段声明成了public
如果我们把delegate1声明为private,就失去了意义,因为他就是为了给让别的类在调用的时候可以直接用,不用重新声明,但是public带来的坏处就是,客户端可以对他进行随意的赋值等操作,对象的封装性会遭到破坏
这时候,event出场了,他封装了委托类型的变量,相当于为委托类型量身定制的属性(Property)。使得:在类的内部,不管声明它是public还是protected,他总是private的。
再次改写GreetingManager类
public delegate void GreetingDelegate(string name);
public class GreetingManager
{
//声明一个事件
public event GreetingDelegate MakeGreet;
public void GreetPeople(string name)
{
MakeGreet(name);
}
}
与之前的委托声明唯一的区别在于多了一个event关键字,类似于声明一个进行了封装的委托类型的变量
这时候,客户端就会出现编译错误
这样在类的外部,方法的绑定和解绑的访问限定符与声明事件时使用的访问限定符相同,解决了一致性的问题。
总结
事件带来了更好的封装性,还能限制含有事件的类型的能力