news 2026/9/14 23:06:29

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/9/15 0:07:53

Wan2.2-T2V-A14B支持自动字幕嵌入吗?多语种翻译生成测试

Wan2.2-T2V-A14B是否支持自动字幕嵌入&#xff1f;多语种翻译能力实测解析 在短视频出海、跨国品牌营销日益频繁的今天&#xff0c;内容本地化的效率直接决定了市场响应速度。一个中国团队制作的广告片&#xff0c;如果需要投放到欧美、东南亚甚至拉美地区&#xff0c;传统流程…

作者头像 李华
网站建设 2026/9/15 9:35:19

Wan2.2-T2V-A14B与Sora的技术路线差异比较

Wan2.2-T2V-A14B与Sora的技术路线差异比较 在生成式AI的浪潮中&#xff0c;文本到视频&#xff08;Text-to-Video, T2V&#xff09;正从“能出画面”迈向“可商用”的关键转折点。过去一年里&#xff0c;我们见证了两个极具代表性的技术里程碑&#xff1a;阿里巴巴推出的 Wan2.…

作者头像 李华
网站建设 2026/9/14 17:20:14

Java两种代理模式详解

如有错误欢迎指出 是jdk动态代理是从一步步开始写完特性/维度JDK 动态代理CGLIB 动态代理是否需要接口✅ 需要接口❌ 不需要接口&#xff08;可代理普通类&#xff09;代理原理基于反射实现接口方法的代理继承目标类并重写方法&#xff0c;基于 ASM 字节码操作代理类结构生成实…

作者头像 李华
网站建设 2026/9/14 18:57:09

MySQL基础篇——约束和事务

事务与隔离级别比较常考1、MySQL约束约束作用于表中字段&#xff0c;在创建/修改表时使用非空约束&#xff0c;唯一约束&#xff0c;主键约束&#xff0c;默认约束&#xff0c;检查约束&#xff0c;外键约束create table user(id int primary key auto_increment comment 主键,…

作者头像 李华
网站建设 2026/9/14 13:54:37

【VSCode量子编程环境搭建指南】:手把手教你5步配置Qiskit开发环境

第一章&#xff1a;VSCode量子编程环境搭建概述 在当前量子计算快速发展的背景下&#xff0c;开发者需要一个高效、灵活且可扩展的开发环境来编写和调试量子程序。Visual Studio Code&#xff08;VSCode&#xff09;凭借其强大的插件生态和轻量级架构&#xff0c;成为构建量子编…

作者头像 李华
网站建设 2026/9/15 0:52:40

Flutter深度解析:从原理到实战的全栈开发指南

Flutter深度解析&#xff1a;从原理到实战的全栈开发指南引言&#xff1a;跨平台开发的革命性突破在移动开发领域&#xff0c;React Native、UniApp等方案曾占据主导地位&#xff0c;但Flutter凭借其独特的自绘引擎和声明式UI范式&#xff0c;已成为构建高性能跨平台应用的首选…

作者头像 李华