es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Combinar delegados: ¿Cómo verificar si un delegado multicast (combinable) ya tiene un delegado dentro de él?

Estoy utilizando Unity 3D, sin embargo, esa información no debería ser relevante para resolver este problema, ya que el problema central es System.Delegate (quería hacértelo saber ya que estaré enlazando a algunos documentos de Unity para aclarar).

Tengo una ventana personalizada que tiene una función de actualización personalizada llamada “DirectorUpdate”. Necesito que esta función se ejecute en cada actualización del editor sin importar lo que esté haciendo el usuario/ventana.

Para que esto se llame en cada actualización del editor, combino mi método con el Delegado EditorApplication.update (https://docs.unity3d.com/ScriptReference/EditorApplication-update.html):

“`C#
protected void OnEnable()
{
// Si hago lo siguiente, la función base EditorApplication.update ya no se llamará.
// EditorApplication.update = this.DirectorUpdate;
// Así que necesito hacer esto:
EditorApplication.update = (EditorApplication.CallbackFunction)System.Delegate.Combine(new EditorApplication.CallbackFunction(this.DirectorUpdate), EditorApplication.update);

<pre><code>… // Otras cosas
</code></pre>

}
“`

Ten en cuenta que esto se hace dentro de un OnEnable de una ventana (https://docs.unity3d.com/ScriptReference/ScriptableObject.OnEnable.html).

El problema es que OnEnable puede ser llamado más de una vez durante una sola ejecución (por ejemplo, al cerrar la ventana y luego volver a abrirla durante una sesión de editor única), lo que provoca que la línea EditorApplication.update = (EditorApplication.CallbackFunction)System.Delegate.Combine(new EditorApplication.CallbackFunction(this.DirectorUpdate), EditorApplication.update); se llame varias veces, lo que significa que mi método de actualización (this.DirectorUpdate) eventualmente se llamará varias veces por actualización, lo que está causando algunos errores graves.

Entonces, la pregunta es ¿cómo puedo verificar si EditorApplication.update ya tiene mi método “dentro” de él? (Cuando digo “dentro” me refiero a que ya se ha combinado System.Delegate.Combine(d) en el delegado).

Soy consciente de que podría haber otras soluciones, por ejemplo, restaurar EditorApplication.update a lo que era antes cuando se cierra la ventana, sin embargo, eso no tendrá en cuenta todas las situaciones (por ejemplo, OnEnable también se llama durante la actualización de la ventana, entre otras cosas) y el error persistirá. (Además, ¿qué sucede si otra ventana se combina con EditorApplication.update mientras esta ventana está abierta?) Por lo tanto, la mejor solución sería verificar si EditorApplication.update ya está llamando a este método ANTES de combinarlo con Delegate.Combine.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Para verificar si EditorApplication.update ya tiene el método this.DirectorUpdate dentro de él, puedes usar el método Delegate.GetInvocationList() para obtener un array de delegados actualmente en el delegado multicast EditorApplication.update. Luego, puedes recorrer este array y comparar cada delegado con this.DirectorUpdate utilizando el método Delegate.Equals(). Si se encuentra una coincidencia, sabrás que el método ya está suscrito al delegado y no es necesario agregarlo nuevamente.

    Aquí tienes una implementación de ejemplo de esta verificación:

    protected void OnEnable()
    {
        Delegate[] editorUpdateDelegates = EditorApplication.update.GetInvocationList();
        bool delegateAlreadyAdded = false;
        foreach (Delegate del in editorUpdateDelegates)
        {
            if (del.Equals(new EditorApplication.CallbackFunction(this.DirectorUpdate)))
            {
                delegateAlreadyAdded = true;
                break;
            }
        }
    
        if (!delegateAlreadyAdded)
        {
            EditorApplication.update = (EditorApplication.CallbackFunction)System.Delegate.Combine(new EditorApplication.CallbackFunction(this.DirectorUpdate), EditorApplication.update);
        }
    
        // Otras cosas
    }
    

    Este código primero obtiene el array de delegados en EditorApplication.update, luego recorre cada delegado para verificar si es el mismo que this.DirectorUpdate. Si se encuentra una coincidencia, se establece delegateAlreadyAdded en true y se sale del bucle. Si no se encuentra ninguna coincidencia, delegateAlreadyAdded permanece en false y el nuevo delegado se concatena a EditorApplication.update.

    Al utilizar esta verificación, puedes evitar agregar el mismo método a EditorApplication.update varias veces y prevenir los errores que pueden surgir al suscribir el mismo método múltiples veces.

Comments are closed.