2008-09-25 9 views
148

¿Hay alguna forma de saber si se ha agregado un controlador de eventos a un objeto? Estoy serializando una lista de objetos dentro/fuera del estado de la sesión para que podamos usar el estado de la sesión basada en SQL ... Cuando un objeto en la lista tiene una propiedad cambiada necesita ser marcado, que el controlador de eventos se ocupó adecuadamente antes . Sin embargo, ahora, cuando los objetos están deserializados, no obtienen el controlador de eventos.¿Ya se ha agregado un controlador de eventos?

En un ataque de leve molestia, acabo de agregar el controlador de eventos a la propiedad Obtener que accede al objeto. Se llama ahora, lo que es genial, excepto que se llama como 5 veces, así que creo que el controlador solo se agrega cada vez que se accede al objeto.

Es bastante seguro ignorarlo, pero preferiría hacerlo mucho más limpio comprobando si el controlador ya se ha agregado, así que solo lo hago una vez.

¿Es esto posible?

EDITAR: No necesariamente tengo control total de los controladores de eventos que se agregan, por lo que solo verifica si no es suficiente.

+0

ver también http://stackoverflow.com/questions/367523/cómo-asegurar-un-evento-está-solamente-suscrito-a-una vez –

Respuesta

107

Desde fuera de la clase que define, como se menciona @Telos, sólo se puede utilizar manejador de sucesos en el lado izquierdo de un += o una -=. Por lo tanto, si tiene la capacidad de modificar la clase de definición, puede proporcionar un método para realizar la comprobación comprobando si el controlador de eventos es null; de ser así, no se ha agregado ningún controlador de eventos. Si no es así, entonces puede y puede recorrer los valores en Delegate.GetInvocationList. Si uno es igual al delegado que desea agregar como controlador de eventos, entonces sabrá que está allí.

public bool IsEventHandlerRegistered(Delegate prospectiveHandler) 
{ 
    if (this.EventHandler != null) 
    { 
     foreach (Delegate existingHandler in this.EventHandler.GetInvocationList()) 
     { 
      if (existingHandler == prospectiveHandler) 
      { 
       return true; 
      } 
     } 
    } 
    return false; 
} 

Y esto podría modificarse fácilmente para convertirse en "agregar el controlador si no está allí". Si no tiene acceso a las entrañas de la clase que está exponiendo el evento, puede necesitar explorar -= y +=, según lo sugerido por @Lou Franco.

Sin embargo, es mejor que reexamine la forma en que está poniendo en servicio y retirando estos objetos, para ver si no puede encontrar una manera de rastrear esta información usted mismo.

+7

Esto no se compila, EventHandler solo puede estar en el lado izquierdo de + = o - =. – CodeRedick

+0

Ah sí. Buen punto. Incorporado. –

+2

Se eliminó el voto a la baja después de una explicación más detallada. El estado SQL está destruyendo la idea aquí ... :( – CodeRedick

18

Si este es el único controlador, puede verificar si el evento es nulo, si no es así, se ha agregado el controlador.

Creo que puede llamar de manera segura - = en el evento con su controlador incluso si no se agrega (si no, podría atraparlo) - para asegurarse de que no está allí antes de agregar.

+2

Esta lógica se interrumpirá tan pronto como el evento sea manejado en otro lugar también. – bugged87

0
EventHandler.GetInvocationList().Length > 0 
+2

¿Esto no arroja cuando la lista == nulo? –

+2

fuera de la clase propietaria del controlador de eventos, solo puede usar - = y + =. no puedes acceder al evento – tbergelt

6

Este ejemplo muestra cómo usar el método GetInvocationList() para recuperar delegados a todos los controladores que se han agregado. Si está buscando ver si se ha agregado un manejador (función) específico, entonces puede usar una matriz.

public class MyClass 
{ 
    event Action MyEvent; 
} 

... 

MyClass myClass = new MyClass(); 
myClass.MyEvent += SomeFunction; 

... 

Action[] handlers = myClass.MyEvent.GetInvocationList(); //this will be an array of 1 in this example 

Console.WriteLine(handlers[0].Method.Name);//prints the name of the method 

Puede examinar varias propiedades en la propiedad Método del delegado para ver si se ha agregado una función específica.

Si está buscando para ver si solo hay uno adjunto, puede probar nulo.

+0

GetInvocationList() no es miembro de mi clase. De hecho, parece que no puedo encontrar este método en ningún objeto o controlador al que tenga acceso ... – CodeRedick

+0

He corregido el código. Es un miembro del evento en cuestión. –

+0

Lo intenté también, aparentemente solo puedes acceder al evento de esa forma desde dentro de la clase. Estoy haciendo esto genéricamente, y como otros han mencionado, los manejadores de eventos probablemente se estén perdiendo de todos modos. ¡Gracias por la aclaración! – CodeRedick

4

Si entiendo su problema correctamente, es posible que tenga problemas mayores. Usted dijo que otros objetos pueden suscribirse a estos eventos. Cuando el objeto se serializa y se deserializa, los otros objetos (aquellos sobre los que no se tiene control) perderán sus controladores de eventos.

Si no está preocupado por eso, mantener una referencia a su controlador de eventos debería ser lo suficientemente bueno. Si le preocupan los efectos colaterales de que otros objetos pierdan sus manejadores de eventos, entonces puede querer reconsiderar su estrategia de almacenamiento en caché.

+1

D'oh! Ni siquiera había pensado en eso ... aunque debería haber sido obvio teniendo en cuenta que mi problema original era que mi propio controlador se perdiera. – CodeRedick

141

Recientemente llegué a una situación similar en la que necesitaba registrar un controlador para un evento solo una vez. He descubierto que se puede anular el registro de seguridad en primer lugar, y luego registrarse de nuevo, incluso si el controlador no se ha registrado en absoluto:

myClass.MyEvent -= MyHandler; 
myClass.MyEvent += MyHandler; 

Tenga en cuenta que hacer esto cada vez que se registre el controlador se asegurará de que el controlador se ha registrado una sola vez . suena como una muy buena práctica para mí :)

+5

Parece arriesgado; si se dispara un evento después de eliminar el controlador y antes de volver a agregarlo, se perderá. – Jimmy

+18

Claro. Quieres decir que no es seguro para subprocesos. Pero eso solo puede ser un problema cuando se ejecutan varios subprocesos o elementos similares, lo que no es habitual. En la mayoría de los casos, esto debería ser lo suficientemente bueno por razones de simplicidad. – alf

+0

Creo que esta es la mejor manera de hacerlo, simplemente practica cuando cada vez que lo agregas lo restas de todos modos, entonces puedes estar más seguro. de lo contrario, se golpeará la cabeza contra la pared al descubrir que se está llamando al mismo método dos veces –

0

estoy de acuerdo con la respuesta de alf, pero muy pocas modificaciones a que es ,, de usar,

  try 
      { 
       control_name.Click -= event_Click; 
       main_browser.Document.Click += Document_Click; 
      } 
      catch(Exception exce) 
      { 
       main_browser.Document.Click += Document_Click; 
      } 
Cuestiones relacionadas