[C#中级] 事件
定义
从概念上理解,事件就是某一个对象向另外一个对象发送一个消息,事件的发送方负责发送,接收方负责接收。
详解
事件,我硬讲,你是肯定不能理解的,因为事件和委托非常相似。事件其实是对委托的封装(封装没忘吧?就是保护)。
委托,就是发起方明确告诉接收方,我需要什么。然后接收方就负责去执行。
事件,就是我给你发送一个信号,而这个信号通常用来暗示你,干什么。
模拟两个场景。
场景1:
发送方:学校
发信号:下课铃
接收方:学生(溜了溜了!)
(接收方,表示收到并且欣然接受)
场景2
发送方:女朋友板着个脸
发信号:"哼"
接收方:怕是有事,但是不知道是什么事。你慌不慌?
(接收方,表示心慌,并希望离开这里!)
场景1很简单,就是明面上,大家约定俗成的一种信号,当接收方接收到信号的时候,明确的知道自己要干什么,并做出与之对应的行为。
场景2也很简单,这个事件不是你触发,也不在约定范围。但是你做为接收方,你接收到了。
举例
声明事件的关键字是event
public event EventNameEventHandler EventName
因为事件是对委托的封装,所以事件在声明时,需要关联一个委托。例子代码中的EventNameEventHandler就是事件与委托关联时的一种约定命名,要求必须是事件名字(EventName) + 固定文字(EventHandler),最后定义事件的名称。
我们用场景2来举例子,首先你要定义一个女朋友类
public class GirlFriend
{
//委托
public delegate void UnhappyEventHandler(Object e, EventArgs args);
//事件
public event UnhappyEventHandler Unhappy;
}
GirlFriend类里面有一个委托和一个事件。用于事件的委托,需要注意的是,在定义时,一定是没有返回值的(void)。其次,必须包含两个参数,第一个参数Object类型通常命名为e,用于指定引发事件的对象。第二个参数为EventArgs类型,用于传递事件所需要的数据。
注意委托的命名,前面有讲过规则。
然后我们实例化一个女朋友,并使用 "+=" 来绑定事件。(此处代码另有乾坤,看后面的两幅图)
static void Main(string[] args)
{
GirlFriend gf = new GirlFriend();
gf.Unhappy += Gf_Unhappy;
Console.ReadLine();
}
private static void Gf_Unhappy(object e, EventArgs args)
{
Console.WriteLine("哼!");
}
注意,在输入完"+="符号后会出现智能提示,只需要按下Tab键,会自动帮你生成事件与之对应的方法。
红框内的是自动生成的
生成出来以后,记得修改生成方法中代码。。。
private static void Gf_Unhappy(object e, EventArgs args)
{
Console.WriteLine("哼!");
}
编码到这里,其实已经完成了对事件的定义,以及事件的注册("+="符号做的就是注册)。但是你运行你会发现,事件并没有被触发。
接下来,我们要做的事情,就是惹"她"生气。 诶~,刺不刺激?
我们回到GrilFriend类中,增加一个方法OnUnhappy()
public class GirlFriend
{
//委托
public delegate void UnhappyEventHandler(Object e, EventArgs args);
//事件
public event UnhappyEventHandler Unhappy;
//提供给外围的调用
public void OnUnhappy()
{
if (Unhappy != null)
{
Unhappy(this, new EventArgs());
}
}
}
这种触发事件的方法,定义时,通常是“On + 事件名”来做为方法名字定义。内部实现时,首先要判断Unhappy 不等于 null。因为外围在实例化GirlFriend类时,可能并没有注册事件,所以事件可能为null。
(!=)一个感叹号,一个等号,是逻辑运算符,不等于的意思。等号很好理解。感叹号是逻辑运算符'非'的意思("这里的非和古语中的'非也非也'作用一样"),就是取反,那么原本的等于,加上感叹号以后就变成了不等于。
然后就是调用事件,在调用定义的事件时,要求传入的参数,就是与事件关联的委托中定义的参数,第一个参数传入this。这里的this代表是自己,即当前对象本身。后面的第二个参数,因为没有,就new一个与之参数类型一样的对象即可。
全部定义完成以后,我们要让她生气!
调用刚才在GirlFriend中定义的OnUnhappy()方法。
static void Main(string[] args)
{
GirlFriend gf = new GirlFriend();
gf.Unhappy += Gf_Unhappy;
gf.OnUnhappy();
Console.ReadLine();
}
最终如愿以偿输出了 "哼"
总结
上述例子,如果你复盘全部代码的话,会有一种,不过是一个方法调用另外一个方法感觉,但是事件的调用在真实的业务场景中,大多数是由类本身去触发,只要你注册了这个事件,你就是事件的接收者,你需要针对该事件去做出响应。
其实这个例子并不是一个能体现事件结构的例子。我只是用了一种最普通的结构来呈现事件。