首页 > 解决方案 > 删除委托的目标后如何安全地使用操作委托

问题描述

我通常使用委托进行回调。例如,我在统一脚本中的管理器中声明 Action 委托,并在调用 OnEnable 时注册委托,并在我的 Monobehaviuor 派生脚本中调用 OnDisable 时取消订阅。但我知道,如果我在错误的时间反抗和反抗,也许会很危险。例如,如果对象被某人删除。委托目标将为空。然后不需要的委托回调就可以了。因此,我想在委托执行时检查委托的目标是否为空,并且我想将其删除,并且我想在同一脚本中调用同一委托时唯一地抵抗委托。我怎样才能安全地使用它?这是我的源示例。

经理班

    public class TestManager : MonoBehaviour
{
    public Action TestDelegate;
    // Use this for initialization
    void Update ()
    {
        if (Input.GetKeyDown("space"))
        {
            if(null != TestDelegate)
            {  
                TestDelegate();
            }
        }
    }
}

对象类

public class WindosTest : MonoBehaviour {

    [SerializeField]
    TestManager _manager;   

    private void Awake()
    {   
        _manager.TestDelegate += Test;
    }

    // Update is called once per frame
    void Update ()
    {
        if (Input.GetKeyDown("d"))
        {
            GameObject.DestroyImmediate(this.gameObject);
        }
    }

    void Test()
    {
        UnityEngine.Debug.LogError("test");
    }
}

标签: c#unity3ddelegates

解决方案


这里的问题是使用 DestroyImmediate 而不是 Destroy。这两者之间的主要区别在于 Destroy 需要正确解构对象,这意味着它将在被销毁之前收到其 OnDisable() 回调(因此它有机会取消订阅委托)。

通常(不在编辑器中)出于安全考虑,最好调用 Destroy() 而不是 DestroyImmediate()。

如果你调用 Destroy(),你会得到正常的 OnDisable 回调,这意味着你可以:

void OnEnable()
{   
    _manager.TestDelegate += Test;
}
void OnDisable()
{   
    _manager.TestDelegate -= Test;
}

推荐阅读