当前位置: 首页 > news >正文

Unity里的delegate, event, Action, Func, UnityEvent, UnityAction和Event

C# / Unity 中 delegate、event、Action、Func、UnityEvent 的简单理解

背景

一直以来,我对各种“事件”的应用都有点迷迷糊糊。

平时写代码的时候,大多就是:

+=-=?.Invoke()

这样直接使用。

但是很多时候看源码,看到delegateeventActionFuncUnityEvent这些东西混在一起,就会有点懵。

所以这次专门花了一些时间翻文章、看代码,把自己的理解记录下来。


1. delegate

1.1 delegate 是什么?

delegate可以理解为一种类型安全的函数指针

它的作用是:

用来存储一个或多个方法,并在需要的时候执行这些方法。

声明delegate的时候,本质上是在声明一个“委托类型”。

之后就可以用这个委托类型去声明变量,并让这个变量指向符合签名的方法。


1.2 delegate 的基本写法

publicdelegatevoidMyDelegate(intnumber);

这行代码的意思是:

声明一个名为MyDelegate的委托类型。

这个委托类型要求绑定的方法必须满足:

  • 无返回值:void
  • 有一个int类型参数

所以,后面只要方法符合这个签名,就可以赋值给MyDelegate类型的变量。


1.3 delegate 使用案例

usingUnityEngine;publicclassTest:MonoBehaviour{publicdelegatevoidMyDelegate(intnumber);privatevoidStart(){MyDelegatedel1=TestFunction1;del1(55);}privatevoidTestFunction1(intnum){Debug.Log("Test1: "+num);}}

这里的执行流程是:

MyDelegatedel1=TestFunction1;

表示把TestFunction1这个方法赋值给del1

然后:

del1(55);

就相当于调用:

TestFunction1(55);

所以最终会输出:

Test1:55

2. event

2.1 event 是什么?

event是一个关键字。

从表现上看,它可以理解为一种受限制的 delegate

它通常和委托类型一起使用。

例如:

publicdelegatevoidMyDelegate(intnumber);publiceventMyDelegatedel2;

这里的del2是一个事件。


2.2 event 和普通 delegate 的区别

在当前类内部,event修饰的委托变量,基本可以像普通委托一样使用:

del2=SomeFunction;del2+=SomeFunction;del2-=SomeFunction;del2?.Invoke(10);

但是在类的外部,event会限制访问权限。

外部类只能:

+=-=

不能直接:

=

也不能直接调用:

del2.Invoke();

2.3 为什么要用 event?

假如不用event,而是直接暴露一个 public delegate:

publicMyDelegatedel;

那么外部类可以直接这样写:

obj.del=null;

这样会把之前所有注册的方法都清空,风险很大。

而使用event后:

publiceventMyDelegatedel;

外部类就只能添加和移除监听:

obj.del+=SomeFunction;obj.del-=SomeFunction;

不能直接覆盖整个事件。

所以event的主要作用是:

保护委托变量,防止外部随意赋值、清空、调用。


2.4 event 的底层理解

可以简单理解为:

event会把委托变量的直接赋值权限限制起来。

外部访问时,只暴露类似下面这样的操作:

addremove

也就是外部的:

+=-=

本质上会走事件的添加和移除逻辑。

=赋值和Invoke调用,只能在声明事件的类内部使用。


3. Action 和 Func

3.1 Action 和 Func 是什么?

ActionFunc都是系统提前封装好的委托类型。

使用它们的好处是:

不需要自己手动声明 delegate,可以直接拿来用。


3.2 Action

Action表示没有返回值的委托。

例如系统内部大概是这样声明的:

namespaceSystem{publicdelegatevoidAction();}

也就是说:

ActionmyAction;

本质上就相当于声明了一个无参数、无返回值的委托变量。

如果需要参数,也可以写:

Action<int>action1;Action<int,string>action2;

3.3 Func

Func表示有返回值的委托。

例如:

namespaceSystem{publicdelegateTResultFunc<inT,outTResult>(Targ);}

常见写法:

Func<int,int>myFunc;

它表示:

  • 传入一个int
  • 返回一个int

最后一个泛型参数永远表示返回值类型。

例如:

Func<int,string,bool>func;

表示:

  • 第一个参数是int
  • 第二个参数是string
  • 返回值是bool

3.4 Action、Func 和 event 一起使用

ActionFunc本身也是委托类型。

所以它们也可以配合event使用。

例如:

publicActionMyAction;publicFunc<int,int>MyFunc;publiceventActionMyActionEvent;

其中:

publicActionMyAction;

外部可以直接赋值、清空、调用。

而:

publiceventActionMyActionEvent;

外部只能+=-=,不能直接赋值或调用。


3.5 代码案例

usingSystem;usingUnityEngine;publicclassTestDelegate:MonoBehaviour{publicActionMyAction;publicFunc<int,int>MyFunc;publiceventActionMyActionEvent;voidStart(){MyAction+=Test3;MyAction+=Test4;MyAction();MyAction=null;Debug.Log("**************");MyFunc=Test5;intresult=MyFunc(77);Debug.Log("Result: "+result);MyFunc=null;Debug.Log("**************");MyActionEvent=Test3;MyActionEvent();MyActionEvent=null;}publicvoidTest3(){Debug.Log("Test3");}publicvoidTest4(){Debug.Log("Test4");}publicintTest5(intnum){Debug.Log("Test5: "+num);returnnum;}}

在当前类TestDelegate内部:

MyActionEvent=Test3;MyActionEvent();MyActionEvent=null;

这些都是合法的。

但是如果在外部类中这样写:

publicclassTest:MonoBehaviour{publicTestDelegatet;privatevoidStart(){t.MyAction=null;t.MyFunc=null;t.MyActionEvent=null;// 非法,外部不能直接赋值 eventt.MyActionEvent?.invoke();//非法,外部不可以调用event标记的事件}}

这里:

t.MyAction=null;t.MyFunc=null;

是合法的。

但是:

t.MyActionEvent=null;t.MyActionEvent?.invoke();

会报错。

因为MyActionEventevent关键字保护了,外部不能直接赋值。

外部只能这样:

t.MyActionEvent+=SomeFunction;t.MyActionEvent-=SomeFunction;

4. UnityAction 和 UnityEvent

4.1 UnityAction

理解了Action之后,UnityAction就很好理解了。

UnityAction是 Unity 内部预先声明好的委托类型。

它和Action很像。

Unity 内部大概是这样声明的:

namespaceUnityEngine.Events{publicdelegatevoidUnityAction();}

所以:

UnityActionaction;

本质上也是一个无参数、无返回值的委托。


4.2 UnityEvent

UnityEvent是 Unity 封装的一套事件系统。

它和普通委托的使用方式不太一样。

普通委托通常是:

+=-=?.Invoke()

UnityEvent通常是:

AddListener RemoveListener Invoke

4.3 UnityEvent 的使用案例

usingUnityEngine;usingUnityEngine.Events;publicclassTest:MonoBehaviour{publicUnityEventMyEvent;voidStart(){MyEvent.AddListener(TestFunction);}privatevoidTestFunction(){Debug.Log("TestFunction");}}

调用事件时:

MyEvent.Invoke();

移除监听时:

MyEvent.RemoveListener(TestFunction);

4.4 UnityEvent 的特点

UnityEvent的一个重要特点是:

可以在 Unity Inspector 面板中显示,并且可以手动拖拽对象和方法进行注册。

这点是普通Actiondelegateevent不具备的。

所以在 Unity 中,UnityEvent常用于:

  • 按钮点击事件
  • Inspector 面板配置事件
  • 不想写死代码,希望策划或美术可以在面板中配置回调
  • 简单的组件通信

5. Event 类

5.1 Event 和 event 不是一个东西

一开始我也容易把Eventevent搞混。

后来查了一下才知道:

Event是 Unity 里的一个类,主要用于OnGUI系统。

它和 C# 的事件委托不是一回事。


5.2 Event.current

在 Unity 的旧版 IMGUI 系统中,每一帧 Unity 会多次推送输入、绘制等事件。

每一次都会生成一个Event对象。

可以通过:

Event.current

获取当前这一次 GUI 事件的数据。

例如:

voidOnGUI(){Evente=Event.current;if(e.type==EventType.MouseDown){Debug.Log("鼠标按下");}}

5.3 Event 常见用途

Event多用于:

  • OnGUI
  • 编辑器扩展
  • 自定义 EditorWindow
  • 自定义 Inspector
  • 旧版 IMGUI 输入处理

它和下面这些概念不是同一类东西:

delegateeventAction Func UnityEvent

所以可以简单记成:

event是 C# 事件关键字。
Event是 Unity 的 GUI 事件数据类。


6. 简单总结

6.1 delegate

delegate是委托类型。

它可以存储符合指定签名的方法,并在需要的时候调用。


6.2 event

event是对委托变量的一层限制。

它可以防止外部类直接赋值、清空和调用事件。

外部只能:

+=-=

6.3 Action

Action是系统封装好的无返回值委托。

例如:

Action Action<int>Action<int,string>

6.4 Func

Func是系统封装好的有返回值委托。

最后一个泛型参数表示返回值类型。

例如:

Func<int,int>Func<int,string,bool>

6.5 UnityAction

UnityAction是 Unity 自己封装的委托类型,和Action很像。


6.6 UnityEvent

UnityEvent是 Unity 封装的事件系统。

它可以通过代码注册监听,也可以在 Inspector 面板中配置监听。

常用方法是:

AddListener RemoveListener Invoke

6.7 Event

Event是 Unity 的 GUI 事件数据类。

它主要用于:

OnGUI Event.current EditorWindow 自定义 Inspector

它和 C# 的event关键字不是一个东西。


7. 最后总结

我现在对这些概念的简单理解是:

delegate:声明一种“方法变量类型” Action / Func / UnityAction:系统或 Unity 提前声明好的委托类型 event:限制外部访问权限的委托变量 UnityEvent:Unity 封装的、支持 Inspector 配置的事件系统 Event:Unity OnGUI / 编辑器系统中的事件数据类
http://www.jsqmd.com/news/1029359/

相关文章:

  • 知识产权商标注册公司推荐:TOP5实力榜评测专业价格注意事项特点 - 品牌推荐
  • 济南打工人闲置黄金变现攻略,全城可上门回收省时又省心 - 开心测评
  • 2026 贵阳大小挖机出租公司 实测 TOP5 真实分享 - LYL仔仔
  • 2026年贵阳装修公司优质品牌推荐:本地靠谱装修企业实力盘点 - 装修新知
  • Wireshark 时间戳显示格式深度定制:从默认视图到精准分析
  • 抖音内容批量下载神器:3步搞定无水印视频自动采集
  • 2026 天津名表回收实地测评,五家靠谱门店,全套避坑攻略收好 - 讯息早知道
  • 从噪声到图像:DDPM反向扩散过程的数学推导与工程实现
  • Linux命令:write
  • 2026年甘肃省PMP培训机构哪家好?官方授权R.E.P.报考指南 - 众智商学院课程中心
  • GitHub加速终极指南:3分钟安装,10倍下载速度提升
  • Claude 4.8 技术观察:开发者该如何把大模型能力真正用到项目里?
  • 盒马鲜生卡回收新增价格表怎么查?实测回收四个挑选途径的核心指标 - 猎卡回收公众号
  • 2026年二手集装箱租赁/回收避坑指南:5个问题帮你省下冤枉钱 - 奔跑123
  • 实地走访德州六家黄金回收店谁更靠谱 - 余生黄金回收
  • 上海手表回收线上估价靠谱吗?5 家门店线上线下报价对比 - 讯息早知道
  • 2026 沈阳贵金属回收横向实测,黄金铂金单克价差完整统计 - 奢侈品回收评测
  • 本溪市2026年奢侈品手表包包回收门店权威测评:这五家店铺回收价格最高 - 谊识预商务
  • LVDS接口硬件设计:从基础理论到高带宽显示应用实战
  • 中文医疗对话数据集:构建专业医疗AI的微调训练基准
  • 告别群消息刷屏!2026最全能的接龙小程序“接龙加加”,这5大高频场景彻底解放你的生产力 - 亲测好用工具
  • 福州市奢侈品手表包包回收价格差距高达15%:实测对比告诉你哪家店报价最实在 - 谊识预商务
  • 国产大模型应用实践指南:从提示词工程到行业知识库搭建
  • 收藏!小白程序员也能掌握的大模型Agent框架Hermes深度解析
  • 2026年长沙门窗五金与硅酮胶供应商全景对标:如何找到真正的一站式配套伙伴 - 优质企业观察收录
  • 2026年6月宁波黄金回收避坑指南 看懂行情选靠谱实体门店 - 润富黄金回收
  • MAA明日方舟助手终极指南:解放双手的全自动游戏体验
  • 深圳奢侈品名表变现测评|仪器鉴表无套路,劳力士宝珀高价出手攻略! - 奢侈品交易观察员
  • 抚州市闲置奢侈品变现必看:手表包包回收门店真实测评汇总 - 谊识预商贸
  • 物理层协议