news 2026/6/9 20:24:28

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/6/8 17:43:10

chrome英文翻译插件

插件下载地址 https://immersivetranslate.com/download/ 基本设置 快捷键

作者头像 李华
网站建设 2026/6/8 11:42:28

量子计算+机器学习调试实战(VSCode高阶技巧全公开)

第一章&#xff1a;量子机器学习的 VSCode 调试在开发量子机器学习应用时&#xff0c;调试是确保算法逻辑正确性和性能优化的关键环节。Visual Studio Code&#xff08;VSCode&#xff09;凭借其强大的扩展生态和灵活的调试配置&#xff0c;成为量子计算开发者首选的集成开发环…

作者头像 李华
网站建设 2026/6/9 12:42:13

电脑系统缺少OpenAL32.dll文件 无法启动软件问题 下载修复

在使用电脑系统时经常会出现丢失找不到某些文件的情况&#xff0c;由于很多常用软件都是采用 Microsoft Visual Studio 编写的&#xff0c;所以这类软件的运行需要依赖微软Visual C运行库&#xff0c;比如像 QQ、迅雷、Adobe 软件等等&#xff0c;如果没有安装VC运行库或者安装…

作者头像 李华
网站建设 2026/6/9 19:43:03

Wan2.2-T2V-A14B在航空管制培训视频中的复杂空域展现

Wan2.2-T2V-A14B在航空管制培训视频中的复杂空域展现 你有没有想过&#xff0c;未来飞行员和空中交通管制员的训练场景&#xff0c;可能不再依赖昂贵的仿真设备或预录动画&#xff0c;而是由一段自然语言描述实时生成&#xff1f;比如输入一句&#xff1a;“雷暴逼近机场&#…

作者头像 李华
网站建设 2026/6/9 19:41:53

论文重复率检测必备:高校认可工具与合格阈值

核心工具对比速览工具名称核心功能查重率控制AI生成率适用场景生成速度aibiye全学科初稿生成15%以内低急需初稿/理工科图表需求20-30分钟aicheck初稿生成查重7%-25%低初稿查重一站式20-30分钟askpaper学术文献辅助--文献综述/数据支撑实时检索秒篇高效初稿生成15%以内低快速产出…

作者头像 李华