¿Cómo puedo borrar suscripciones a eventos en C#?


Tome la siguiente clase de C#:

c1 {
 event EventHandler someEvent;
}

Si hay muchas suscripciones al evento c1 y quiero borrarlas todas, ¿cuál es la mejor manera de lograrlo? También considere que las suscripciones a este evento podrían ser/son lambdas/delegados anónimos.

Actualmente mi solución es agregar un método ResetSubscriptions() a c1 que establezca someEvent en null. No se si esto tiene consecuencias invisibles.

Author: Jason Plank, 2008-09-30

9 answers

Desde dentro de la clase, puede establecer la variable (oculta) en null. Una referencia nula es la forma canónica de representar una lista de invocaciones vacía, efectivamente.

Desde fuera de la clase, no puedes hacer esto - los eventos básicamente exponen "subscribe" y "unsubscribe" y eso es todo.

Vale la pena ser consciente de lo que están haciendo realmente los eventos de tipo campo: están creando una variable y un evento al mismo tiempo. Dentro de la clase, terminas haciendo referencia a la variable. Desde fuera, usted hace referencia al evento.

Vea mi artículo sobre eventos y delegados para más información.

 168
Author: Jon Skeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-09 22:44:32

Agregue un método a c1 que establecerá 'SomeEvent' en null...

class c1
{
    event EventHandler someEvent;
    ResetSubscriptions() {someEvent = null;}
}
 28
Author: programmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-25 09:20:05
class c1
{
    event EventHandler someEvent;
    ResetSubscriptions() {someEvent = delegate{};}
}

Es mejor usar delegate{} que null

 7
Author: Feng,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-30 16:33:55

Establecer el evento en null dentro de la clase funciona. Cuando dispones de una clase siempre debes establecer el evento en null, el GC tiene problemas con los eventos y puede que no limpie la clase dispuesta si tiene eventos colgando.

 6
Author: Jonathan C Dickinson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-01 11:17:04

La mejor práctica para borrar todos los suscriptores es establecer el SomeEvent a null agregando otro método público si desea exponer esta funcionalidad al exterior. Esto no tiene consecuencias invisibles. La condición previa es recordar declarar SomeEvent con la palabra clave 'event'.

Por favor, vea el libro - C# 4.0 en pocas palabras, página 125.

Aquí alguien propuso usar el método Delegate.RemoveAll. Si lo usa, el código de ejemplo podría seguir el siguiente formulario. Pero es realmente estúpido. ¿Por qué no solo SomeEvent=null dentro de la función ClearSubscribers()?

   public void ClearSubscribers ()
    {
          SomeEvent = (EventHandler) Delegate.RemoveAll(SomeEvent, SomeEvent);// Then you will find SomeEvent is set to null.
    }
 6
Author: Cary,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-20 14:38:43

Puede lograr esto usando el Delegado.Eliminar o delegar.RemoveAll métodos.

 5
Author: Micah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-30 15:36:21

Comentario aburrido extendido conceptual.

Prefiero usar la palabra "controlador de eventos" en lugar de "evento" o "delegado". Y usó la palabra "evento" para otras cosas. En algunos lenguajes de programación (VB.NET, Object Pascal, Objective-C)," event "se llama" message "o" signal", e incluso tiene una palabra clave" message " y una sintaxis específica de sugar.

const
  WM_Paint = 998;  // <-- "question" can be done by several talkers
  WM_Clear = 546;

type
  MyWindowClass = class(Window)
    procedure NotEventHandlerMethod_1;
    procedure NotEventHandlerMethod_17;

    procedure DoPaintEventHandler; message WM_Paint; // <-- "answer" by this listener
    procedure DoClearEventHandler; message WM_Clear;
  end;

Y, para responder a ese "mensaje", un "controlador de eventos" responde, ya sea un único delegado o varios delegado.

Resumen: "Evento" es la "pregunta", "controlador (es) de evento" son las respuestas.

 3
Author: umlcat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-24 19:07:30

Esta es mi solución:

public class Foo : IDisposable
{
    private event EventHandler _statusChanged;
    public event EventHandler StatusChanged
    {
        add
        {
            _statusChanged += value;
        }
        remove
        {
            _statusChanged -= value;
        }
    }

    public void Dispose()
    {
        _statusChanged = null;
    }
}

Debe llamar a Dispose() o usar using(new Foo()){/*...*/} pattern para cancelar la suscripción de todos los miembros de la lista de invocaciones.

 1
Author: Jalal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-05 07:14:39

Elimine todos los eventos, asuma que el evento es un tipo de "Acción":

Delegate[] dary = TermCheckScore.GetInvocationList();

if ( dary != null )
{
    foreach ( Delegate del in dary )
    {
        TermCheckScore -= ( Action ) del;
    }
}
 0
Author: Googol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-12-20 20:00:54