删除委托人的目标后,如何安全使用动作委托

时间:2018-12-17 07:33:29

标签: c# unity3d delegates

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

经理阶层

    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");
    }
}

2 个答案:

答案 0 :(得分:1)

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

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

如果调用Destroy(),将获得正常的OnDisable回调,这意味着您可以执行以下操作:

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

答案 1 :(得分:0)

您已经在做,除非我误解了这个问题

如果要使其更短,请按以下步骤进行操作,但是由于已经在检查null,因此您的代码可以正常工作

TestDelegate?.Invoke();