Delegate.Combine:如何检查多播(可组合)委托中是否已有委托?

Delegate.Combine: How to Check if multicast (combinable) delegates already has a delegate inside of it?

我正在使用 Unity 3D,但是,该信息应该与解决此问题无关,因为核心问题是 System.Delegate(我想让你知道,因为我将链接到一些 Unity 文档澄清)。

我有一个自定义 window,它具有自定义更新功能 DirectorUpdate。我需要这个函数来 运行 每个编辑器更新,不管 user/window 在做什么。

为了在每次编辑器更新时调用它,我将我的方法与委托结合起来 EditorApplication.update:

protected void OnEnable()
{
    // If I do the below, base EditorApplication.update won't be called anymore.
    // EditorApplication.update = this.DirectorUpdate;
    // So I need to do this:
    EditorApplication.update = (EditorApplication.CallbackFunction)System.Delegate.Combine(new EditorApplication.CallbackFunction(this.DirectorUpdate), EditorApplication.update);

    ... // Other stuff
}

请注意,这是在 window 的 OnEnable 中完成的。

问题是在单个 运行 期间可以多次调用 OnEnable(例如,关闭 window 然后重新打开window 在单个编辑器会话期间)导致

EditorApplication.update = (EditorApplication.CallbackFunction)System.Delegate.Combine(new EditorApplication.CallbackFunction(this.DirectorUpdate), EditorApplication.update);

被多次调用, 意味着我的更新方法 (this.DirectorUpdate) 每次更新最终都会被调用多次,这会导致一些严重的错误。

所以,问题是我如何检查EditorApplication.update是否已经在其中“包含”了我的方法。 (在里面,我当然是说它已经 System.Delegate.Combine(d) 给代表了。)

我知道可能还有其他解决方案,例如将 EditorApplication.update 恢复到 window 关闭之前的状态,但这并不能解决所有情况(例如, OnEnable 也会在 window 刷新等期间被调用)并且错误将持续存在。 (此外,如果另一个 window 与 EditorApplication.update 连接,而此 window 处于打开状态怎么办?)因此,最好的解决方案是检查 EditorApplication.update 是否已经调用此方法在 Delegate.Combine-ing 之前。

我不熟悉 System.Delegate.Combine(d) 的作用,但您可以考虑用 window 代替 enabling/disabling,每次都销毁并实例化它,然后将您的代码移动到 StartAwake 每次 window “激活”仅调用一次。

最后但同样重要的是,在 OnDisable 中使用一个强大的布尔值,这样您就可以在您的组件被禁用时处理联合执行。像这样:

bool omgIWasDisabled;
protected void OnEnable()
{
    if (!omgIWasDisabled) {
        EditorApplication.update = (EditorApplication.CallbackFunction)System.Delegate.Combine(new EditorApplication.CallbackFunction(this.DirectorUpdate), EditorApplication.update);
    }
   
    ... // Other stuff
}  

void OnDisable() {
    omgIWasDisabled = true;
}

希望这些都能解决。

我认为你走的路很复杂;)

订阅和取消订阅事件和委托就像使用运算符 += and -= like

一样简单
protected void OnEnable()
{
    // You can substract your callback even though it wasn't added so far
    // This makes sure it is definitely only added once (for this instance)
    EditorApplication.update -= DirectorUpdate;
    
    // This basically internally does such a Combine for you
    EditorApplication.update += DirectorUpdate;
    
    ... // Other stuff
}

private void OnDisable()
{
    // Remove the callback once not needed anymore
    EditorApplication.update -= DirectorUpdate;
}

这样你也可以打开这个 window 的多个实例,它们都将单独接收回调。


顺便说一句,如果这实际上是关于 EditorWindow 那么 afaik 你不应该使用 OnEnabled 但你宁愿使用 Awake

Called as the new window is opened.

OnDestroy.