2009-02-21 615 views
22

Necesito copiar los suscriptores de un evento a otro. ¿Puedo obtener los suscriptores de un evento (como MyEvent [0] devolver un delegado)?¿Cómo obtengo los suscriptores de un evento?

Si esto no es posible, usaría el complemento para agregar los delegados a una lista. ¿Esa sería la mejor solución?

Respuesta

20

C# events/deletes son multidifusión, por lo que el delegado es sí mismo una lista. Desde dentro de la clase, para obtener las llamadas individuales, puede utilizar:

if(field != null) { // or the event-name for field-like events 
    // or your own event-type in place of EventHandler 
    foreach(EventHandler subscriber in field.GetInvocationList()) 
    { 
     // etc 
    } 
} 

Sin embargo, para asignar a la vez, sólo tiene que utilizar + = o asignación directa:

SomeType other = ... 
other.SomeEvent += localEvent; 
+0

Gracias por señalar eso. Eso es lo mejor para los eventos en mi propio código. – weiqure

+0

Muchas gracias por esto. Necesitaba una buena solución para la clonación de objetos a través de la serialización binaria que no disfrutaba de los eventos suscritos, o de lo contrario habría tenido que implementar ICloneable en varios cientos de clases. – user1039513

3

Actualización (gracias a los comentaristas): la inmunidad del delegado significa que la clonación no logra nada en una asignación.

Cuando uno escribe:

myDelegate += AHandler 

una nueva instancia de delegado se crea y se asigna a myDelegate.

Por lo tanto, el siguiente código funcionaría exactamente igual sin la llamada Clone.


MulticastDelegate (el tipo subyacente) tiene un método Clone.

Para poder llegar al delegado subyacente es posible que deba evitar el helper habitual que genera la palabra clave del evento, y administrar cosas directamente (agregar y eliminar accesadores personalizados).

Para mostrar esto:

 
    class Program { 
     public delegate void MyDelegate(string name); 

     public event MyDelegate EventOne; 

     public void HandlerOne(string name) { 
      Console.WriteLine("This is handler one: {0}", name); 
     } 
     public void HandlerTwo(string name) { 
      Console.WriteLine("This is handler two: {0}", name); 
     } 
     public void HandlerThree(string name) { 
      Console.WriteLine("This is handler three: {0}", name); 
     } 

     public void Run() { 
      EventOne += HandlerOne; 
      EventOne += HandlerTwo; 
      Console.WriteLine("Before clone"); 
      EventOne("EventOne"); 

      
            
 
  
             MyDelegate eventTwo = (MyDelegate)EventOne.Clone();
            
  
      MyDelegate eventTwo = EventOne; 
      Console.WriteLine("After 
            
 
  
             clone
            
 copy"); 
      EventOne("EventOne"); 
      eventTwo("eventTwo"); 

      Console.WriteLine("Change event one to show it is different"); 
      EventOne += HandlerThree; 
      EventOne("EventOne"); 
      eventTwo("eventTwo"); 
     } 

     static void Main(string[] args) { 
      (new Program()).Run(); 
     } 
    } 
+0

Clon en sí es relativamente poco importante - los delegados son inmutables, lo que sólo puede copiar la referencia delegado. –

+0

A menos que, como en la muestra, desee modificar el original o copiar de forma independiente. – Richard

+0

Richard - no, eso funcionaría ** idénticamente ** sin el paso Clonar(). –

13

Si el evento es uno publicado por otra clase, no se puede - al menos, no de forma fiable. Si bien a menudo pensamos que un evento es simplemente una variable de delegado, en realidad se trata de un par de métodos: agregar y eliminar (o suscribirse y cancelar suscripción).

Si es su propio código el que publica el evento, es fácil: puede hacer que los usuarios accedan o eliminen lo que quieran.

Eche un vistazo a my article on events y vea si eso lo ayuda. De lo contrario, brinde más detalles sobre lo que quiere hacer, especificando qué bits de código puede modificar y cuáles no.

1

En caso de que necesite para examinar los suscriptores de un evento externo de clase:

EventHandler e = typeof(ExternalClass) 
    .GetField(nameof(ExternalClass.Event), BindingFlags.Instance | BindingFlags.NonPublic) 
    .GetValue(instanceOfExternalClass) as EventHandler; 
if (e != null) 
{ 
    Delegate[] subscribers = e.GetInvocationList(); 
} 
Cuestiones relacionadas