废话不多说,先贴代码,同样希望大家上机测试,运行,在分析每行代码的作用,每行代码作用我已经上注释
/*
*
* 事件注册方:
* 目的:负责事件的注册,至于事件什么时候调用,如何调用不关心
*
*
*/
using System;
using System.Collections.Generic;
/// <summary>
/// 商业项目中事件与委托的应用
/// </summary>
namespace 学习事件与委托
{
/// <summary>
/// 事件注册方
/// </summary>
public class RegisterClass
{
//注册方的构造函数 我们一般在注册方对象被构造出来的时候就注册自己关心的事件,说白了就是把直接的方法赛塞到
//调用方也就发事件那边的一个事件变量当中,这个变量你可以看成是函数指针,可以保存很多的函数。
public RegisterClass()
{
InvokeClass.eveInform += new InformHandler(InformZhangSan); //把自己的行为和事件调用方的事件进行绑定 或者叫注册事件
InvokeClass.eveInform += InformLiSi; //把自己的行为和事件调用方的事件进行绑定 或者叫注册事件
InvokeClass.eveInform += InformNewComer; //把自己的行为和事件调用方的事件进行绑定 或者叫注册事件
}
public void InformZhangSan(string name) //注册方的行动
{
Console.WriteLine("{0},张三 老板来了。", name); //注册方的行动
}
public void InformLiSi(string name) //注册方的行动
{
Console.WriteLine("{0},李四 老板来了。", name);
}
public void InformNewComer(string name) //注册方的行动
{
Console.WriteLine("{0},新同事 老板来了。", name);
}
}
}
/*
*
* 事件调用方:
* 目的:负责事件的调用,至于事件调用后,产出哪些功能,不关心
*
*
*/
using System;
using System.Collections.Generic;
/// <summary>
/// 商业项目中事件与委托的应用
/// </summary>
namespace 学习事件与委托
{
//定义委托
public delegate void InformHandler(string name);
/// <summary>
/// 事件调用方
/// </summary>
public class InvokeClass
{
//声明事件 这里我们用static方便注册方直接通过类名访问这个变量
public static event InformHandler eveInform; //事件实例 用于注册方把自己的行为或者叫方法注册进来
/// <summary>
/// 调用事件(显示内容)
/// </summary>
public void DisplayInfo()
{
if(eveInform != null) //调用注册方的方法的时候,首先必须检测有没有人监听了你的事件。
{
eveInform("我是前台小张"); //有人监听我的事件,我开始发事件并且给注册者一个实参,注册方使用
}
}
}
}
“`
using System;
using System.Collections;
using System.Collections.Generic;
///
/// 商业项目中事件与委托的应用
///
namespace 学习事件与委托
{
/// <summary>
/// 测试方:整合前2者功能,实现"访问者设计模式"
/// </summary>
class TestClass
{
//程序入口函数,写法固定
static void Main(string[] args)
{
//先运行事件的注册 因为我们这边不需要拿到注册方的实例对象
new RegisterClass(); //注意我们的事件注册就是在构造函数里注册的
//在运行事件的调用
InvokeClass invoke = new InvokeClass(); //需要拿到调用方的对象
invoke.DisplayInfo();//开始测试
}
}
}
下面来谈事件和委托的区别首先委托定义是可以在类的外部,事件的定义是必须在类里面
上图
假如我们把事件定义放在类外面试试
其实我们也知道事件就是委托的一个实例,委托其实就是类,那么通过类+变量名的形式,既然是变量是肯定不然放在类外的,根据语法层面我们也知道。
现在我们来证明事件就是委托 的一个实例变量
我们在注册方需要给调用方法的事件变量注册一个行为,我们其实也就是new了一个委托实例给这个实例绑定一个方法。
那么现在我们来谈加了这个event关键字的作用,其实我们就可以看成这个关键字限制了后面的委托实例的或者叫委托对象的操作行为,比如委托可以= += -= 3种操作,但是event修饰的不能进行=操作 以及事件只能限制在调用方触发 不能在其他类里触发 ,但是委托是可以的
我们上代码
大家发现了吗,你在其他类里虽然可以访问到这个加了event事件关键字修饰的委托实例,但是是无法进行调用的。
但是如果我们通过不加event关键字修饰的委托实例,去调用的话可以吗。
现在测试是可以在外界触发的。
那么问题来了:比如我出版社,那么我有个出版书籍的事件,那么想要出版书的人就关心我这个事件,要出版书籍了就告诉他们,那么这个事件肯定是只能出版社的才能发出,其他发出这个事件算个啥事。
因此我们event关键字就做这个功能把事件的触发限制在当前的对象当中。这个好处面试的时候一定是最重要的。以及事件注册方比如想要发表书籍的人他不主动会关注出版社什么时候出版,出版社什么时候要出版书籍你发个通知就可以,以及出版社他不会管什么人监听了这个事件,他只需要发出要出版书籍这个通知,至于你关注这个事件的人是谁,有多少人,出版社是不管的。因此事件把事件关注方和调用方完全解耦,当新的关注事件的人增加,事件的调用方不需要改任何代码也就是这个代码。
我相信说完这些还是蒙的人看完我这个举例会明白:
假如我开发了一个游戏:游戏中有主角以及显示主角的那个详细信息的UI界面。
那么我们主角有血的多少吧,我们在主角脚本中用一个float变量表示假如,我们UI界面的对于主角多少血肯定是根据主角这个变量多少时时的去更新到VIew视图也就是UI上。因此我们如果采用事件委托形式的话,我们定义一个血变化事件,在UI view层级上写一个关于拿到主角血变量的函数进行更新视图,是不是可以。
现在这个更新UI的函数我们可以看成是关系主角血变化这个事件的,因为需要注册,这样主角这个血变了就会发个事件触发注册的函数,并且把血变量发给注册者,更新到UI上。其实血变化这个事件你这个更新ui的函数不注册可以吗。可以啊,主角的血变量事件不会关心谁注册了,以及你注册后实现什么,不关心。还有就是血事件什么触发,注册方他会关心吗,什么时候触发,也不会关系,我们这里比如主角被敌人打了,调血了主角就发出血变化这个事件。注册方得到了就更新UI视图,所以注册方也是不需要知道主角事件啥时候触发的。随意吧,就是敌人啥时候打主角都可以,不是确定。
、
你觉得这个调用方会因为注册者的增加而去改代码吗,肯定不会。
事件关注方可以增加任意个方法。