1、事件的本质
事件是对委托的进一步封装,本质还是委托,
事件是干嘛的:
用于对象或类间的动作协调与信息传递。
我们来这样理解:
“发生→响应”:闹钟响铃了我起床,分为五个部分
闹钟,响铃,我,起床
其中还有一个隐含的部分为:订阅
也就是我订阅了我手机的铃声,手机响铃时,我才会发生反应。如果是别人的手机,我没有订阅,就算响铃,我也不会有反应。
事件的用处:
事件多用于桌面、手机等开发的客户端编程,因为这些程序经常是用户通过事件来“驱动”的。
2、事件的定义
event 委托类型 事件名
static void Main(string[] args)
{
EventDo ev = new EventDo();
ev._del += OpenCamera; //订阅,+=是订阅事件的操作符
ev.Do(); //触发这里在winform里面不需要我们来触发
Console.ReadKey();
}
//具体方法的定义
public static void OpenCamera(object sender,EventArgs e)
{
Console.WriteLine("我被响应了");
}
}
//在winform里面,以下的操作是不需要你写的
public class EventDo
{
public event EventHandler _del; //事件变量的定义
public void Do() //调用
{
_del(this,new EventArgs());
}
}
3、为什么需要事件
为了程序的逻辑更加“有道理”,更加安全
4、事件和委托区别
1、事件只用去定义具体的方法和绑定,不需要我们调用(触发);
委托一般需要自己定义调用
2、事件不能在类外部触发,不能作为参数传递;
委托事件可以在类外部触发,可以作为参数传递
3、事件是安全的,委托在一定程度上是不安全的
5、什么时候使用事件,什么时候使用委托
事件:触发机制(某个消息发生才调用某个方法)用事件
委托:当你想传递方法参数,或者一个类想调用另一个类的方法用委托
6、事件的使用
事件的使用一般通过发布者(触发事件)和订阅者(事件对应具体方法实现)来进行。发布者会在某一条件下触发某事件,订阅者可以通过订阅该事件,来对该事件的触发做出反应
namespace 事件详细理解
{
class Program
{
static void Main(string[] args)
{
Publisher pub = new Publisher();
Subscriber sub = new Subscriber();
// 1、通过事件发布器来触发事件,然后订阅器接收该事件
pub.NumChange += new NumCountChange(sub.OnNumChange);
pub.InvokeEvent(); //发布者触发事件,订阅者接收该触发事件
//pub.NumChange(14); //事件在外部触发会报错
// 2、通过委托则可以在外部直接触发该事件,为可行但不合理的方式
pub.NumChangeDelegate = new NumCountChange(sub.OnNumChange);
pub.NumChangeDelegate(200);//委托变量直接调用了订阅者的OnNumChange函数
Console.ReadKey();
}
}
/// <summary>
/// 声明委托类型
/// </summary>
/// <param name="num"></param>
public delegate void NumCountChange(int num);
/// <summary>
/// 事件发布者类
/// </summary>
class Publisher
{
public NumCountChange NumChangeDelegate; //声明委托类型变量
public event NumCountChange NumChange; //声明事件
public int count { set; get; } = 99;
//当调用该函数时,由发布者来触发对应的事件
public void InvokeEvent()
{
if (NumChange != null) //当委托中有函数注册时(即为非空),就会触发该事件
{
++count;
NumChange(count);//触发该事件
}
}
}
/// <summary>
/// 事件订阅者类
/// </summary>
class Subscriber
{
//该函数会注册到委托事件中,一旦事件发布者触发该事件时,订阅者就会接收到该事件进行执行
public void OnNumChange(int count)
{
Console.WriteLine("Subscriber the changed number is {0}", count);
}
}
}
7、事件中的观察者模式
1、事件触发模式
事件的触发和反应是一种观察者模式,主要由两部分组成:
被监视者:相当于事件发布者,其中有一些属性来被其它对象所监视。
观察者:相当于事件的订阅者,它会观察被监视对象的某些属性,当这些属性发生变化时,会触发观察者做出对应的反应。观察者一般可以有多个。
被监视对象只管触发事件,而不管是否有人订阅了该事件。
观察者只根据自身的需要,来决定是否需要注册订阅该事件,以对该事件产生响应,而不管是谁触发了该事件
具体实例
加热水的加热器,时刻显示水温的显示器,当水温达到90度时的报警器。这三者来共同组成该程序,代码如下:
namespace 事件详解2
{
class Program
{
static void Main(string[] args)
{
Heater heater = new Heater();
Alarm alarm = new Alarm();
Display display = new Display();
heater.curTemperature += alarm.MakeAlarm; //将报警函数注册到事件上
heater.curTemperature += display.ShowTemperature; //将显示温度函数注册到事件上
heater.Heating();//开始加热
}
}
public delegate void SendTemperatureEvent(int num);
/// <summary>
/// 加热器:负责加热。相当于事件发布者,用来发布当前水温。
/// </summary>
class Heater
{
public event SendTemperatureEvent curTemperature;
private int temperature; //水温
private int maxTemp = 100;
public void Heating()
{
//水温从85度开始
for (int i = 85; i <= maxTemp; ++i)
{
temperature = i;
if (curTemperature != null)
{
curTemperature(temperature); //触发事件
}
Thread.Sleep(1000); //线程睡眠1秒
}
Console.WriteLine("现在水温 100℃ !!!");
Console.ReadKey();
}
}
/// <summary>
/// 报警器:当水温达到一定的值时,进行报警
/// </summary>
class Alarm
{
//订阅者:从加热器那里订阅水温,当水温达到一定值,就开始报警。
public void MakeAlarm(int temperature)
{
if (temperature > 90)
{
Console.WriteLine($"现在水温 {temperature}");
}
}
}
/// <summary>
/// 显示器:显示水温值
/// </summary>
class Display
{
//订阅者:从加热器那里订阅水温,并进行显示。
public void ShowTemperature(int temperature)
{
Console.WriteLine($"水温 :{temperature}");
}
}
}