在Unity开发中,C#的委托(Delegate)和事件(Event)就像一对双胞胎兄弟,曾困惑于它们的本质区别。本文将通过实战案例揭开这对”孪生兄弟”的神秘面纱,了解它们的正确使用姿势。
一、委托:灵活的函数指针
1.1 委托的本质
委托本质上是一个类型安全的函数指针容器,可以存储多个方法引用。我们可以通过+=运算符实现多播委托:
public delegate void HealthHandler(float health);
public class Player {
    public HealthHandler OnHealthChanged;
    public void TakeDamage(float damage) {
        currentHealth -= damage;
        OnHealthChanged?.Invoke(currentHealth);
    }
}
1.2 委托的妙用场景
- 实现回调系统(如成就解锁)
 - 跨脚本通信(非MonoBehaviour类间通信)
 - 异步操作处理(如资源加载完成回调)
 
二、事件:安全的委托封装器
2.1 事件的核心特征
事件在委托基础上添加了访问控制层,使用event关键字声明:
public class Achievements {
    public event Action OnAchievementUnlocked;
    private void Unlock(string achievementName) {
        OnAchievementUnlocked?.Invoke(achievementName);
    }
}
2.2 事件的安全机制
- 封装性:外部类只能订阅/取消订阅(+=/-=)
 - 访问控制:仅声明类可触发事件
 - 线程安全:编译器自动生成线程同步代码
 
三、关键差异对比表
| 特性 | 委托 | 事件 | 
|---|---|---|
| 访问权限 | 公共可调用 | 仅声明类可触发 | 
| 赋值操作 | 支持=赋值 | 仅支持+=/-= | 
| 多播能力 | 原生支持 | 通过委托机制支持 | 
| 空引用检查 | 需手动检查 | 自动生成空检查代码 | 
| 设计目的 | 通用回调机制 | 观察者模式实现 | 
| 典型应用场景 | 函数参数、回调列表 | UI交互、游戏事件通知 | 
四、Unity实战案例解析
4.1 委托实现技能冷却系统
public class SkillSystem {
    public delegate void CooldownCallback(int skillID);
    public CooldownCallback OnCooldownStart;
    public void CastSkill(int skillID) {
        // 释放技能逻辑
        OnCooldownStart?.Invoke(skillID);
    }
}
// 使用端
skillSystem.OnCooldownStart += id => Debug.Log($"技能{id}开始冷却");
4.2 事件实现成就系统
public class AchievementSystem {
    public event Action<string> OnAchievementCompleted;
    public void CompleteAchievement(string name) {
        OnAchievementCompleted?.Invoke(name);
    }
}
// 订阅端
achievementSystem.OnAchievementCompleted += name => {
    PlayEffect(name);
    UpdateUI(name);
};
五、设计选择指南
✅ 使用委托当:
- 需要函数作为参数传递时
 - 实现回调函数列表时
 - 需要直接控制调用时
 
✅ 使用事件当:
- 构建发布-订阅系统时
 - 需要保护触发权限时
 - 处理UI交互事件时
 - 实现系统解耦时
 
六、性能优化贴士
- 避免每帧触发高频事件(如Update中的物理检测)
 - 及时取消订阅防止内存泄漏
 - 对高频事件使用EventManager集中管理
 - 值类型参数优先使用ref传递
 - 使用对象池重用事件参数
 
结语
理解委托和事件的区别就像掌握魔法世界中的两种咒语:委托是灵活的基础咒语,而事件则是施加了保护咒的强化版本。在Unity开发中,建议80%的场景使用事件,仅在需要完全控制调用时使用原始委托。记住:事件不是委托的替代品,而是其安全封装形态。合理运用这对黄金组合,可以让游戏代码既优雅又高效!