【超详细】C#事件
目录
事件是一种特殊的委托,那什么是委托呢?简而言之,委托是一种数据类型(关键字delegate);委托代表的是方法;当调用委托时就是调用了这个方法。想要进一步了解委托,可以参考【一文了解】C#重点-委托1、【一文了解】C#重点-委托2了解委托的定义、3个基本使用步骤、单播委托和多播委托、实例化委托的四种方法。
事件
1.定义
事件(event)是声明为委托类型的类的成员,允许一个类或对象通知其他类或对象某个特定的事情已经发生。事件基于委托。表示类的偶发行为,一旦这个行为发生,往往要引起其他行为/方法发自动执行。事件是用来实现两个或多个行为的联动调用的。简而言之,事件(关键字event)是声明为委托类型的类的成员变量,是一种特殊的委托。
2.特点
事件发生后,其他对象做出响应。事件是一种观察者模式的实现方式。
观察者模式
定义
一个对象(被观察者)维护一组依赖于它的对象(观察者)。当被观察者的状态发生变化时,所有的观察者都会被通知并作出相应的反应。通过这种方式,观察者模式实现了松耦合的设计,使得事件源和响应者之间不需要直接依赖彼此。
重要概念
1)事件源(被观察者):定义事件,并负责触发事件。
2)响应者(观察者):订阅事件,并响应事件。
如:张三骂李四,李四打张三 (事件源:张三,响应者:李四)
3.使用步骤(重点)
步骤严格固定:定义端①③ 调用端②④
①声明事件
首先要定义一个委托,该委托定义了事件处理程序的签名(返回类型和参数列表)
public delegate void MyEventHandler(object sender, EventArgs e);
然后在类中声明事件
public event 委托类型 事件名;
②注册事件
写法1(传统写法):事件源对象.事件 += new 委托类型(响应方法)
写法2(简化写法):事件源对象.事件 += 响应方法
注意: += 注册/订阅事件,-= 取消注册/退订事件
③触发事件
事件会在类的某个方法中触发。为了触发事件,需要使用Invoke方法,但为了防止在没有订阅者时引发 NullReferenceException,一般使用?.Invoke()。
④调用包含触发事件的方法
处理思路:
首先要思考当前问题是否需要使用事件(分析行为是否有联动性),即是否行为1发生后行为2会跟着发生?如果还是不能理解,那可以将事件的处理做为一种因果关系来加以理解。
1)因:事件触发
事件的触发是一个原因,它可以由发布者(事件源)内部的某些操作或状态变化引发。
如,在用户界面中,当用户点击关闭按钮(因),会导致按钮的点击事件被触发。
2)果:事件处理
事件处理方法的执行是结果,即订阅者(响应者)在事件被触发时执行的操作。
如,当按钮的点击事件被触发,事件处理方法被执行,窗口关闭(果)。
总结:事件源(发布者)负责触发事件。响应者(订阅者)负责处理事件。事件的目的是用来解决联动性的问题,主要功能是进行通知。
4.使用场景
在GUI开发中,当用户点击按钮时,按钮会触发点击事件,其他对象可以订阅该事件并执行相应的操作。
在多线程编程中,一个线程可以触发事件通知其他线程某些状态的变化。
在游戏开发中,当角色的状态发生变化(如生命值变化、位置变化),可以触发相应的事件,让其他对象做出响应。
5.优势
①解耦:事件允许发布者和订阅者之间的解耦,发布者不需要知道谁订阅了事件,订阅者也不需要知道事件是如何触发的,只需要关注自己的处理逻辑。
②封装:事件只能在声明事件的类中触发,外部类只能订阅或取消订阅,保证了封装性和安全性,防止外部代码意外触发事件。
③多播:事件可以是多播的,即可以有多个订阅者,当事件触发时,所有订阅者的处理程序会依次调用。
6.限制
事件只能在声明的类中触发,外部类无法直接触发或修改事件,只能订阅或取消订阅。
事件一般用于通知,不建议在事件处理程序中返回值,因为多个订阅者的情况下,无法处理多个返回值。
7.举例
下面我们来通过案例来加以理解。
7.1.猫叫,鼠跑人醒。
分析:
①找到行为:叫,跑,醒
②分析行为是否有联动性,可以从案例看出行为有联动性,因为猫叫了,所以老鼠跑了,主人惊醒了。接着分析,原因(叫)的行为作为事件,结果(跑,醒)的行为作为普通方法。然后根据事件的使用步骤来完成案例
using UnityEngine;
namespace EventTest
{
//猫叫,鼠跑人醒
//调用端
public class CatEvent : MonoBehaviour
{
private void Start()
{
Mouse mouse = new Mouse();
Host host = new Host();
//②注册事件
//事件源:因 响应方法:果
//写法1:传统方法
//事件源对象.事件+=new 委托类型(响应方法);
Cat cat = new Cat();
cat.MiaoMiao += new CatHandler(mouse.Run);
//写法2:简化写法
//事件源对象.事件+=响应方法;
cat.MiaoMiao += host.Awake;
//④调用触发事件的方法
cat.Notify();
}
}
//定义端
//①定义事件
//先定义委托,委托代表的是方法,调用委托就是调用方法
public delegate void CatHandler();
class Cat
{
//再定义事件,事件是类中为委托类型的成员
public event CatHandler MiaoMiao;
public void Notify()
{
Debug.Log("猫:Miao miao~");
//③触发事件
MiaoMiao?.Invoke();
}
}
//3)响应方法
class Mouse
{
public void Run()
{
Debug.Log("老鼠:逃跑");
}
}
class Host
{
public void Awake()
{
Debug.Log("主人:惊醒");
}
}
}
输出结果:
7.2.老鹰冲下来,小鸡逃跑,狗叫。
分析:
①找到行为:冲,跑,叫
②分析行为是否有联动性,可以从案例看出行为有联动性,因为猫叫了,所以老鹰冲下来,所以小鸡逃跑,狗叫。接着分析,原因(叫)的行为作为事件,结果(跑,醒)的行为作为普通方法。然后根据事件的使用步骤来完成案例。
using UnityEngine;
namespace EventTest
{
//老鹰冲下来,小鸡逃跑,狗叫
//调用端
public class EagleEvent : MonoBehaviour
{
private void Start()
{
Chick chick = new Chick();
Dog dog = new Dog();
Eagle eagle = new Eagle();
//②注册事件
//事件源:因 响应方法:果
//写法1:传统方法
//事件源对象.事件+=new 委托类型(响应方法);
eagle.Swoop += new EagleSwoopHandler(chick.Run);
//写法2:简化写法
//事件源对象.事件+=响应方法;
eagle.Swoop += dog.WangWang;
//④调用触发事件的方法
eagle.Notify();
}
}
//定义端
//①定义事件
//定义委托 委托代表的是方法,调用委托就是调用方法
public delegate void EagleSwoopHandler();
class Eagle
{
//①定义事件
public event EagleSwoopHandler Swoop;
public void Notify()
{
Debug.Log("老鹰:冲下来");
//③触发事件
Swoop?.Invoke();
}
}
//响应方法
class Chick
{
public void Run()
{
Debug.Log("小鸡:逃跑");
}
}
class Dog
{
public void WangWang()
{
Debug.Log("小狗:Wang wang~");
}
}
}
输出结果:
好了,本次的分享到这里就结束啦,希望对你有所帮助~
原文地址:https://blog.csdn.net/grapefruit_lyy/article/details/145285593
免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!