news 2026/4/23 12:10:02

C# 委托/事件/UnityEvent 详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C# 委托/事件/UnityEvent 详解

1. 委托 (Delegate)

1.1 基本概念

委托是C#中的一种类型,它允许将方法作为参数传递,类似于C/C++中的函数指针,但类型安全。

1.2 委托声明与使用

基本语法:

csharp

// 1. 声明委托类型 delegate void MyDelegate(string message); delegate int CalculateDelegate(int a, int b); // 2. 使用委托 public class DelegateExample { // 定义与委托匹配的方法 static void DisplayMessage(string msg) { Console.WriteLine($"Message: {msg}"); } static int Add(int a, int b) => a + b; static int Multiply(int a, int b) => a * b; static void Main() { // 创建委托实例 MyDelegate messageDelegate = new MyDelegate(DisplayMessage); // 调用委托 messageDelegate("Hello Delegate!"); // 多播委托示例 CalculateDelegate calcDelegate = Add; calcDelegate += Multiply; // 添加另一个方法 // 调用多播委托(会依次调用所有方法,但只返回最后一个结果) int result = calcDelegate(3, 4); // 返回Multiply的结果:12 } }
内置委托类型:

csharp

// Action委托(无返回值) Action<string> action1 = (msg) => Console.WriteLine(msg); Action<int, int> action2 = (x, y) => Console.WriteLine(x + y); // Func委托(有返回值) Func<int, int, int> func1 = (a, b) => a + b; Func<string, int> func2 = (s) => s.Length; // Predicate委托(返回bool) Predicate<int> isEven = (num) => num % 2 == 0;

2. 事件 (Event)

2.1 事件概念

事件是基于委托的特殊类型,提供了发布-订阅模式,增强封装性(外部只能订阅/取消订阅,不能触发)。

2.2 标准事件模式

csharp

public class EventPublisher { // 1. 定义事件委托(标准模式使用EventHandler<T>) public event EventHandler<MyEventArgs> MyEvent; // 2. 定义事件参数类 public class MyEventArgs : EventArgs { public string Message { get; set; } public DateTime Time { get; set; } } // 3. 触发事件的方法 protected virtual void OnMyEvent(string message) { MyEvent?.Invoke(this, new MyEventArgs { Message = message, Time = DateTime.Now }); } public void DoSomething() { // 业务逻辑... OnMyEvent("Something happened!"); } } public class EventSubscriber { public void Subscribe(EventPublisher publisher) { // 订阅事件 publisher.MyEvent += HandleEvent; } private void HandleEvent(object sender, EventPublisher.MyEventArgs e) { Console.WriteLine($"Event received: {e.Message} at {e.Time}"); } } // 使用示例 var publisher = new EventPublisher(); var subscriber = new EventSubscriber(); subscriber.Subscribe(publisher); publisher.DoSomething();

2.3 自定义委托事件

csharp

public class TemperatureMonitor { // 自定义委托 public delegate void TemperatureChangedHandler(float oldTemp, float newTemp); // 基于自定义委托的事件 public event TemperatureChangedHandler TemperatureChanged; private float _temperature; public float Temperature { get => _temperature; set { if (_temperature != value) { float oldTemp = _temperature; _temperature = value; TemperatureChanged?.Invoke(oldTemp, _temperature); } } } }

3. UnityEvent

3.1 UnityEvent特点

UnityEvent是UnityEngine.Events命名空间下的类,专为Unity编辑器集成设计,支持序列化和可视化配置。

3.2 基本用法

csharp

using UnityEngine; using UnityEngine.Events; public class UnityEventExample : MonoBehaviour { // 1. 声明UnityEvent(无参数) [SerializeField] private UnityEvent onStartEvent; // 2. 声明带参数的UnityEvent [System.Serializable] public class StringEvent : UnityEvent<string> { } [SerializeField] private StringEvent onMessageEvent; // 3. 声明多个参数的UnityEvent [System.Serializable] public class DamageEvent : UnityEvent<GameObject, float, Vector3> { } [SerializeField] private DamageEvent onDamageTaken; void Start() { // 代码方式添加监听器 onStartEvent.AddListener(OnStartHandler); onMessageEvent.AddListener(OnMessageHandler); // 触发事件 onStartEvent.Invoke(); onMessageEvent.Invoke("Hello from code!"); } void OnStartHandler() { Debug.Log("Start event triggered!"); } void OnMessageHandler(string message) { Debug.Log($"Message: {message}"); } // 触发带多个参数的事件 public void TakeDamage(float amount, Vector3 hitPoint) { onDamageTaken.Invoke(gameObject, amount, hitPoint); } void OnDestroy() { // 清理监听器(重要!避免内存泄漏) onStartEvent.RemoveAllListeners(); onMessageEvent.RemoveAllListeners(); } }

3.3 编辑器中的可视化配置

在Unity Inspector中,UnityEvent会显示可配置的界面:

  1. 点击"+"添加事件条目

  2. 拖拽GameObject到Object字段

  3. 选择组件和方法

  4. 可以设置参数值

3.4 实际应用示例

csharp

// 开关系统示例 public class Switch : MonoBehaviour { public UnityEvent onTurnOn; public UnityEvent onTurnOff; private bool _isOn = false; public void Toggle() { _isOn = !_isOn; if (_isOn) onTurnOn.Invoke(); else onTurnOff.Invoke(); } } // 使用Switch的门 public class Door : MonoBehaviour { public void Open() { // 开门动画/逻辑 transform.position += Vector3.up * 2; Debug.Log("Door opened!"); } public void Close() { // 关门动画/逻辑 transform.position -= Vector3.up * 2; Debug.Log("Door closed!"); } } // 在Unity编辑器中: // 1. 将Switch脚本添加到开关对象 // 2. 将Door脚本添加到门对象 // 3. 在Switch的Inspector中: // - 拖拽门对象到onTurnOn事件 // - 选择Door.Open方法 // - 拖拽门对象到onTurnOff事件 // - 选择Door.Close方法

4. 三者的比较与选择

特性DelegateEventUnityEvent
封装性低(外部可调用)高(外部只能订阅)
序列化不支持不支持支持
编辑器集成可视化配置
性能较低(有额外开销)
多播支持
使用场景纯代码回调代码事件系统Unity编辑器交互

5. 最佳实践

5.1 内存管理

csharp

public class EventManager : MonoBehaviour { private Dictionary<string, UnityEvent> eventDictionary; void Start() { eventDictionary = new Dictionary<string, UnityEvent>(); } public void StartListening(string eventName, UnityAction listener) { if (!eventDictionary.ContainsKey(eventName)) eventDictionary[eventName] = new UnityEvent(); eventDictionary[eventName].AddListener(listener); } public void StopListening(string eventName, UnityAction listener) { if (eventDictionary.ContainsKey(eventName)) eventDictionary[eventName].RemoveListener(listener); } public void TriggerEvent(string eventName) { if (eventDictionary.ContainsKey(eventName)) eventDictionary[eventName].Invoke(); } void OnDestroy() { // 清理所有事件 foreach (var unityEvent in eventDictionary.Values) { unityEvent.RemoveAllListeners(); } eventDictionary.Clear(); } }

5.2 性能优化建议

  1. 避免频繁事件触发:特别是在Update方法中

  2. 使用对象池:对于频繁创建/销毁的事件参数

  3. 缓存委托实例:避免每次调用都创建新的委托

  4. 谨慎使用匿名方法:可能导致难以调试的内存泄漏

5.3 设计模式应用

csharp

// 观察者模式实现 public interface IObserver { void OnNotify(string eventType, object data); } public class Subject : MonoBehaviour { private List<IObserver> observers = new List<IObserver>(); public void RegisterObserver(IObserver observer) { observers.Add(observer); } public void UnregisterObserver(IObserver observer) { observers.Remove(observer); } protected void NotifyObservers(string eventType, object data = null) { foreach (var observer in observers) { observer.OnNotify(eventType, data); } } }

总结

  1. 委托:是基础,用于方法引用和回调

  2. 事件:基于委托,提供更好的封装,适合组件间通信

  3. UnityEvent:Unity专用,提供编辑器集成,适合非程序员配置

在Unity开发中:

  • 使用C#事件处理纯代码逻辑

  • 使用UnityEvent处理需要在编辑器中配置的交互

  • 两者可以结合使用,发挥各自优势

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/19 19:36:37

NVIDIA Profile Inspector完全攻略:释放显卡隐藏性能

NVIDIA Profile Inspector完全攻略&#xff1a;释放显卡隐藏性能 【免费下载链接】nvidiaProfileInspector 项目地址: https://gitcode.com/gh_mirrors/nv/nvidiaProfileInspector NVIDIA Profile Inspector是一款能够深度挖掘NVIDIA显卡性能的利器。与官方控制面板相比…

作者头像 李华
网站建设 2026/4/21 23:24:35

腾讯用“LLM+GNN“双剑合璧,广告推荐GMV暴涨2.8%!小白也能学会的冷启动解决方案

摘要 传统的广告召回单一模型往往难以有效平衡“语义精准”与“关系覆盖”、“冷启动”与“实时性”之间的结构性矛盾。为应对这一挑战&#xff0c;腾讯广告技术团队提出了融合 LLM 与 GNN 的创新方案&#xff0c;采用“GNN挖掘关系、LLM解析语义”的协同机制。 该方案既保留了…

作者头像 李华
网站建设 2026/4/21 4:39:36

B站视频智能转文字工具:让视频内容轻松变文本

B站视频智能转文字工具&#xff1a;让视频内容轻松变文本 【免费下载链接】bili2text Bilibili视频转文字&#xff0c;一步到位&#xff0c;输入链接即可使用 项目地址: https://gitcode.com/gh_mirrors/bi/bili2text 还在为手动记录视频内容而烦恼吗&#xff1f;每天面…

作者头像 李华
网站建设 2026/4/23 13:51:49

Wan2.2-T2V-A14B已被纳入高校数字艺术课程教学案例库

Wan2.2-T2V-A14B已被纳入高校数字艺术课程教学案例库 在数字内容创作门槛不断降低的今天&#xff0c;一个学生只需输入“敦煌飞天在星空中起舞&#xff0c;衣袂飘飘如云卷云舒”&#xff0c;几秒钟后就能看到一段流畅、细腻、极具东方美学意境的视频片段——这不再是科幻场景&a…

作者头像 李华
网站建设 2026/4/22 1:31:51

GPT-5.2:人工智能的创造力,能否超越人类的想象力?

AI与人类创作的对比 随着GPT-5.2的发布&#xff0c;人工智能在创作领域的表现让人惊叹不已。从写作到设计&#xff0c;再到音乐和艺术创作&#xff0c;GPT-5.2的能力不断扩展&#xff0c;令人不禁思考&#xff1a;人工智能的创造力&#xff0c;真的能够超越人类的想象力吗&…

作者头像 李华
网站建设 2026/4/20 20:47:05

R语言量子计算模拟资源稀缺曝光:仅剩5个开源包可实战,别再错过

第一章&#xff1a;R语言量子计算模拟的现状与挑战随着量子计算研究的不断深入&#xff0c;传统编程语言在模拟量子系统中的作用日益凸显。R语言作为统计计算与数据可视化的主流工具&#xff0c;近年来也被尝试用于量子态模拟和基础量子算法实现。尽管其并非专为高性能数值计算…

作者头像 李华