Unity事件处理器无法取消订阅问题求助
解决Unity事件处理器无法取消订阅的问题
看起来你遇到的问题根源有两个,咱们一个个拆解清楚:
1. 匿名委托导致的订阅/取消不匹配
你在装备槽代码里用的是匿名委托(比如slot => OnDropEvent(slot)),每次写这个表达式的时候,C#都会生成一个全新的委托实例。这意味着:
- 你用
+=添加的是委托实例A - 之后用
-=试图移除的是完全不同的委托实例B
这两个实例不相等,所以事件处理器根本不会被成功移除。
而你背包的代码能正常工作,大概率是因为EventHelper是一个固定的具名方法引用,或者背包的切换逻辑只执行了一次,没有重复订阅的累积问题。
修复方案:用具名方法替代匿名委托
先定义一个和OnDropEvent签名匹配的固定方法:
// 定义统一的事件处理方法 private void HandleEquipmentDrop(Slot slot) { OnDropEvent(slot); }
之后订阅和取消事件时,直接使用这个方法的引用:
// 订阅事件 CharacterItem.MC_EquipmentSlots[i].OnDropEvent += HandleEquipmentDrop; // 取消订阅 CharacterItem.MC_EquipmentSlots[i].OnDropEvent -= HandleEquipmentDrop;
这样每次订阅和取消用的都是同一个委托实例,就能正确匹配并移除事件处理器了。
2. 在Update中处理事件订阅的隐藏风险
你把事件订阅/取消的逻辑放在了Update方法里,这意味着每帧都会执行这段代码。哪怕你切换了角色,之前每帧添加的订阅都会累积,导致同一个事件被订阅了几十甚至几百次。就算你后来尝试取消,也只能移除最后一次添加的那个,之前的订阅依然会触发,让你误以为取消失败。
修复方案:把切换逻辑移到角色切换的触发点
不要在Update里循环检查General.charActive,而是把这段订阅/取消的逻辑放在角色切换的触发事件里:
- 比如角色选择按钮的
OnClick回调 - 或者
General.charActive值变更的事件回调(如果有定义的话)
这样代码只会在角色切换的时候执行一次,既避免了重复订阅,也能确保所有订阅都被正确取消。
完整修复示例
假设你有一个角色切换的回调方法,比如OnCharacterChanged(int newCharIndex),可以这样写:
private void OnCharacterChanged(int newCharIndex) { // 先取消所有角色的事件订阅(避免遗漏) for (int i = 0; i < CharacterItem.equipmentSlots; i++) { CharacterItem.MC_EquipmentSlots[i].OnDropEvent -= HandleEquipmentDrop; CharacterItem.Merc1_EquipmentSlots[i].OnDropEvent -= HandleEquipmentDrop; CharacterItem.Merc2_EquipmentSlots[i].OnDropEvent -= HandleEquipmentDrop; CharacterItem.Merc3_EquipmentSlots[i].OnDropEvent -= HandleEquipmentDrop; } // 再给当前激活的角色添加订阅 switch(newCharIndex) { case 0: for (int i = 0; i < CharacterItem.equipmentSlots; i++) { CharacterItem.MC_EquipmentSlots[i].OnDropEvent += HandleEquipmentDrop; } break; case 1: for (int i = 0; i < CharacterItem.equipmentSlots; i++) { CharacterItem.Merc1_EquipmentSlots[i].OnDropEvent += HandleEquipmentDrop; } break; // 其他角色的逻辑... } }
这样每次切换角色时,先清空所有可能的订阅,再给当前角色添加新的订阅,就不会出现残留的事件处理器了。
内容的提问来源于stack exchange,提问作者Albet Swanto
相关产品推荐
相关产品推荐

