这篇文章是我学习 C# 语言过程中对委托(delegate)和事件(event)的一些简单理解和记录。刚开始接触这两个概念时觉得有点抽象,不太明白它们和普通方法调用有什么区别,也搞不清它们之间的关系。
后来通过查资料、写了一些小例子,慢慢有了一些初步的认识。这里整理一下我学到的内容,包括基本语法、调用过程、委托和事件的区别,以及我自己的理解,方便以后复习,也希望对其他正在学习的人有一点点参考价值
委托(Delegate)
基本定义与使用
委托其实就是方法的引用,本质上就是一种类型安全的函数指针。我们可以通过委托来把某个方法赋值给一个变量,然后在合适的时候调用这个变量,相当于间接调用方法。
下面是一个简单的例子:
1 | // 定义一个返回 int、参数为 int 的委托类型 |
这里我们定义了一个NumberChanger委托类型的变量nc并且将一个方法赋值给他,因为我们的签名一致(传入值和返回值的类型都一致),所以我们在传入10的时候会逐步调用委托中的方法,例子中会执行AddNum。
疑惑:为什么要用委托而不直接使用方法?
这里我一开始觉得好像有点多余,因为我明明可以直接使用这个方法对吧,为什么要多此一举用这个委托去添加呢。
简要来说就是委托的作用是“把方法当作参数或变量来使用”,它让程序具有更高的灵活性、扩展性和解耦性。
举个例子:
普通方法调用(写死了):
1 | public class Button |
这种方式耦合死了,只能点击就执行 ShowPanel,不能变通。
使用委托(可以动态绑定):
1 | public class Button |
外部就可以自由绑定行为:
1 | button.OnClick = ShowPanel; |
这里注意到委托是可以通过+=来为其添加方法的,也就是说可以委托多个方法。我可以在外部去订阅这个委托,从而能够灵活的决定我要执行什么方法;
事件(Event)
基本理解
事件可以理解为“更安全、更受控的委托”。它是委托的封装,只能在声明它的类中触发(Invoke),外部只能 += 添加,不能直接调用,这就确保了订阅机制的封闭性。
举个例子:
先定义一个事件
1 | // 声明一个事件用的委托类型 |
使用事件的类
1 | public class Subscriber |
具体使用
1 | Publisher publisher = new Publisher(); |
看起来和委托很像是不是,确实很像,区别就在于事件的封闭性更高,外部只能对其增改不能赋值,而且他是一个private的,也就是说外部不能去触发这个事件。
| 项目 | 委托 | 事件 |
|---|---|---|
| 是否可以被外部触发 | ✅ 可以 | ❌ 不能(更安全) |
| 外部是否可以覆盖 | ✅ = 可重写 |
❌ 只能 += / -= |
| 是否适合做通知 | 可以,但不推荐 | ✅ 专门为“通知订阅者”设计 |
| 是否解耦 | 部分解耦 | ✅ 更符合发布者/订阅者结构 |
用一句更加C#的话来说就是:事件是”只能订阅,不能随便调用“的安全委托。——事件的触发权限是受限制的,只有定义它的类内部可以调用 .Invoke(),外部只能订阅,不能主动调用,这就保证了调用逻辑的封闭性和安全性。
用途
在游戏中主要用于模块间的消息通知、游戏逻辑解耦、监听玩家行为或系统状态变化。
我自己目前接触和理解的,比如我写一个gameover的一个方法,我需要在游戏结束的时候让场上发生一些变化,比如怪物播放胜利动画,场景变换等等;
这个时候我可以用事件去管理这个部分,例如:
1 | // 发布者(比如 GameManager) |
这个时候委托和事件的优势就体现出来了,我场上的物体是在动态变化的,比如怪物,那他死了之后就不能继续播放动画了对吧,生成了之后就加入这个需要播放的列表。这个时候我就可以在OnEnable和DisAble中去写,在启用的时候将播放动画的方法订阅到这个事件,结束的时候取消订阅。
哎,就很好用。