0

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

我有一个具有自定义更新功能的自定义窗口DirectorUpdate。无论用户/窗口在做什么,我都需要这个函数来运行每个编辑器更新。

为了在每次编辑器更新时调用它,我将我的方法与 Delegate 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
}

请注意,这是在窗口的OnEnable内完成的。

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

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

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

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

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

4

2 回答 2

1

我认为您走的是复杂的道路;)

+=订阅和取消订阅事件和委托就像使用操作符-=一样简单

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

这样,您还可以打开此窗口的多个实例,它们都将单独接收回调。


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

在新窗口打开时调用。

OnDestroy

于 2021-12-14T10:57:35.657 回答
0

我不熟悉做什么System.Delegate.Combine(d),但你可以考虑而不是启用/禁用你的窗口,每次都销毁和实例化它,然后将你的代码移动到Startor ,Awake以便每个窗口“激活”只调用一次。

最后但并非最不重要的一点是,在组件中使用强大的布尔值,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;
}

希望其中任何一个都能解决。

于 2021-12-14T00:01:19.123 回答