Pregunta

Toma la siguiente clase de C #:

c1 {
 event EventHandler someEvent;
}

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

Actualmente mi solución es agregar un método ResetSubscriptions () a c1 que establece someEvent en nulo. No sé si esto tiene alguna consecuencia invisible.

¿Fue útil?

Solución

Desde dentro de la clase, puede establecer la variable (oculta) en nulo. Una referencia nula es la forma canónica de representar una lista de invocación vacía, de manera efectiva.

Desde fuera de la clase, no puedes hacer esto: los eventos básicamente exponen " suscribe " y " cancelar suscripción " y eso es todo.

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

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

Otros consejos

Agregue un método a c1 que establecerá 'someEvent' en nulo ...

class c1
{
    event EventHandler someEvent;
    ResetSubscriptions() {someEvent = null;}
}
class c1
{
    event EventHandler someEvent;
    ResetSubscriptions() {someEvent = delegate{};}
}

Es mejor usar delegado {} que nulo

Establecer el evento en nulo dentro de la clase funciona. Cuando desecha una clase, siempre debe establecer el evento en nulo, el GC tiene problemas con los eventos y puede que no limpie la clase eliminada si tiene eventos pendientes.

La mejor práctica para eliminar a todos los suscriptores es establecer el someEvent en nulo 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 'evento'.

Consulte el libro - C # 4.0 en pocas palabras, página 125.

Alguien aquí propuso utilizar 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.
    }

Puedes lograr esto usando los métodos Delegate.Remove o Delegate.RemoveAll.

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), " evento " se llama un mensaje " " o " señal " ;, e incluso tiene un " mensaje " palabra clave, y sintaxis de azúcar específica.

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 " responda, ya sea un solo delegado o varios delegados.

Resumen: " Evento " es la " pregunta " ;, " controlador (es) de eventos " son la (s) respuesta (s).

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 al Dispose () o usar usando (nuevo Foo ()) {/*...*/} para cancelar la suscripción de todos los miembros de la lista de invocaciones .

Eliminar todos los eventos, suponga que el evento es una " Acción " escribe:

Delegate[] dary = TermCheckScore.GetInvocationList();

if ( dary != null )
{
    foreach ( Delegate del in dary )
    {
        TermCheckScore -= ( Action ) del;
    }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top