2011-08-11 9 views
7

Tengo el siguiente manejador de sucesos:invocación de un manejador de sucesos

private EventHandler<MyEventArgs> _myEventHandler; 
public event EventHandler<MyEventArgs> MyEvent 
{ 
    add { _myEventHandler += value; } 
    remove { _myEventHandler -= value; } 
} 

Podría alguien explicar la diferencia entre los siguientes fragmentos?
fragmentos manejador de sucesos (A):

//Snippet A: 
if (_myEventHandler != null) 
{ 
    _myEventHandler(new MyEventArgs()); 
} 

fragmentos BeginInvoke (B):

//Snippet B: 
if (_myEventHandler != null) 
{ 
    _myEventHandler.BeginInvoke(new MyEventArgs(), ar => 
    { 
    var del = (EventHandler<MyEventArgs>)ar.AsyncState; 
    del.EndInvoke(ar); 
    }, _myEventHandler); 
} 

Para mayor claridad: ¿Cuál es la diferencia entre la invocación de un manejador de sucesos "tal como es" y el uso de BeginInvoke?

Respuesta

12

El enfoque BeginInvoke es asíncrono, lo que significa que se ha generado en un hilo diferente. Esto puede ser peligroso si las personas no lo esperan, y es bastante raro para los eventos, pero puede ser útil.

Además, tenga en cuenta que en sentido estricto debe instantánea el valor controlador de eventos - esto es especialmente cierto si (a través de Begin*) se trata de hilos.

var tmp = _myEventHandler; 
if(tmp != null) { 
    tmp(sender, args); 
} 

también - en cuenta que su suscripción a eventos en sí no es seguro para subprocesos; de nuevo, esto solo ocurre si se trata de múltiples hilos, pero el evento de campo como incorporado es flujos seguros:

public event EventHandler<MyEventArgs> MyEvent; // <===== done; nothing more 

Los problemas se evitan aquí son:

  • con la instantánea , evitamos el riesgo de que el último suscriptor se desuscriba entre el cheque nulo y el invoke (significa que pueden obtener un evento que no esperaban, pero significa que no eliminamos el hilo de subida)
  • con el cambio de evento de tipo campo evitamos el riesgo de perder suscripciones/desuscripciones cuando dos hilos están haciendo esto, al mismo tiempo
+1

No se requiere necesariamente un hilo diferente, ¿verdad? Llamar a un delegado de forma asincrónica todavía se realiza en el mismo hilo, pero regresa en el momento en que bloquea AFAIK. –

+1

@Jeff no; llamar a un delegado asincrónicamente significa que ocurre en un hilo de trabajo. ¿De qué otra forma se ejecutaría de forma asíncrona? Tenga en cuenta que esto es sutilmente diferente de Control.BeginInvoke, que * podría * continuar en el mismo subproceso si ya está en el subproceso UI –

+0

Si el delegado al que se llama realiza el control IO (es decir, bloques) se devuelve al sitio de llamada. Cuando eso se completa, el hilo original se interrumpe para terminar el resto del método. Tal como lo entendí, no se crean nuevos hilos, todo es interrupciones a partir de ahí. –

5

BeginInvoke() llamada devuelve immediatelly control al subproceso de llamada y ejecutar un delegado en un hilo separado del ThreadPool, por lo que esta será una especie de ejecución asíncrona.

Cuestiones relacionadas