You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:03:17