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

Unity抽象类订阅Action重复执行问题排查求助

问题原因与解决方案

核心问题

你遇到的Action重复执行问题,本质是抽象方法的委托引用不匹配导致订阅未被正确取消。

在C#中,委托是基于方法引用绑定的。当你在抽象类RideUIManager的OnEnable里订阅抽象方法OnReward时,实际绑定的是抽象方法的引用;但子类AdvancedRideUIManager重写OnReward后,对象实际执行的是子类的重写方法。当OnDestroy执行取消订阅时,你试图移除的是抽象方法的引用,而非子类重写后的方法引用——这就导致订阅没有被真正移除,多次触发OnEnable(比如对象禁用后重新启用)就会累积多个委托,最终onAdReward调用时重复执行。

解决方案

方案1:将抽象方法改为虚方法

把抽象类中的OnReward改为虚方法,让子类重写时保持委托引用的一致性:

修改RideUIManager.cs:

public abstract class RideUIManager : MonoBehaviour
{
    ...

    protected virtual void OnEnable()
    {
        SRTAdManager.instance.onAdReward += OnReward;
    }

    protected virtual void OnDestroy()
    {
        SRTAdManager.instance.onAdReward -= OnReward;
    }
    
    // 改为虚方法,子类可重写
    protected virtual void OnReward(string rewardType)
    {
        // 空实现或默认逻辑
    }
    ...
}

修改AdvancedRideUIManager.cs:

public class AdvancedRideUIManager : RideUIManager
{
    // 无需额外重写OnEnable/OnDestroy,除非有自定义逻辑
    protected override void OnReward(string rewardType)
    {
        if (rewardType.Equals("MoneyBonusADV"))
        {
                reward *= 2;
                doubleItButton.SetActive(false);
                rewardText.text = reward.ToString();
        }
        if (rewardType.Equals("BonusTimeADV"))
        {
                loseModalWindowManager.ModalWindowOut();
                advancedRide.advancedRide.remaningTime = rewardInfo.bonusTime;
                advancedRide.hasTime = true;
                advancedRide.enumared = false;
                GameEventManager.GameEventPost(
                    "Bonus Time"
                );
                SetAudio(false);
                Time.timeScale = 1;
        }
    }
}

方案2:子类自行处理订阅取消

让抽象类把订阅逻辑交给子类,确保订阅和取消的是子类自己的OnReward方法:

修改RideUIManager.cs:

public abstract class RideUIManager : MonoBehaviour
{
    ...

    protected abstract void OnEnable();
    
    protected abstract void OnDestroy();
    
    public abstract void OnReward(string rewardType);
    ...
}

修改AdvancedRideUIManager.cs:

public class AdvancedRideUIManager : RideUIManager
{
    protected override void OnEnable()
    {
        SRTAdManager.instance.onAdReward += OnReward;
    }

    protected override void OnDestroy()
    {
        SRTAdManager.instance.onAdReward -= OnReward;
    }

    public override void OnReward(string rewardType)
    {
        // 原有逻辑...
    }
}

额外检查点

  • 确认SRTAdManager单例唯一:检查Awake逻辑是否正确,避免场景中存在多个实例导致事件重复触发。
  • 检查AdvancedRideUIManager实例数量:确保场景中只有一个该组件实例,避免多实例同时订阅事件。

内容的提问来源于stack exchange,提问作者Yusuf Salih Tunçel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 22:57:50