Para responder tu pregunta:
- La generación de un evento bloquea el hilo si todos los controladores de eventos se implementan sincrónicamente.
- Los controladores de eventos se ejecutan secuencialmente, uno tras otro, en el orden en que están suscritos al evento.
Yo también tenía curiosidad por el mecanismo interno de eventy sus operaciones relacionadas. Así que escribí un programa simple y solía ildasmhurgar en su implementación.
La respuesta corta es
- no hay ninguna operación asincrónica involucrada en la suscripción o invocación de eventos.
- El evento se implementa con un campo de delegado de respaldo del mismo tipo de delegado.
- la suscripción se realiza con
Delegate.Combine()
- darse de baja se hace con
Delegate.Remove()
- La invocación se realiza simplemente invocando al delegado combinado final
Esto es lo que hice. El programa que utilicé:
public class Foo
{
// cool, it can return a value! which value it returns if there're multiple
// subscribers? answer (by trying): the last subscriber.
public event Func<int, string> OnCall;
private int val = 1;
public void Do()
{
if (OnCall != null)
{
var res = OnCall(val++);
Console.WriteLine($"publisher got back a {res}");
}
}
}
public class Program
{
static void Main(string[] args)
{
var foo = new Foo();
foo.OnCall += i =>
{
Console.WriteLine($"sub2: I've got a {i}");
return "sub2";
};
foo.OnCall += i =>
{
Console.WriteLine($"sub1: I've got a {i}");
return "sub1";
};
foo.Do();
foo.Do();
}
}
Aquí está la implementación de Foo:

Tenga en cuenta que hay un campo OnCall y un evento OnCall . El campo OnCalles obviamente la propiedad de respaldo. Y es simplemente un Func<int, string>, nada lujoso aquí.
Ahora las partes interesantes son:
add_OnCall(Func<int, string>)
remove_OnCall(Func<int, string>)
- y como
OnCallse invoca enDo()
¿Cómo se implementa la suscripción y cancelación de suscripción?
Aquí está la add_OnCallimplementación abreviada en CIL. La parte interesante es que se utiliza Delegate.Combinepara concatenar dos delegados.
.method public hidebysig specialname instance void
add_OnCall(class [mscorlib]System.Func`2<int32,string> 'value') cil managed
{
// ...
.locals init (class [mscorlib]System.Func`2<int32,string> V_0,
class [mscorlib]System.Func`2<int32,string> V_1,
class [mscorlib]System.Func`2<int32,string> V_2)
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Func`2<int32,string> ConsoleApp1.Foo::OnCall
// ...
IL_000b: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
// ...
} // end of method Foo::add_OnCall
Asimismo, Delegate.Removese utiliza en remove_OnCall.
¿Cómo se invoca un evento?
Para invocar OnCallen Do(), simplemente llama al delegado concatenada final después de cargar el arg:
IL_0026: callvirt instance !1 class [mscorlib]System.Func`2<int32,string>::Invoke(!0)
¿Cómo se suscribe exactamente un suscriptor a un evento?
Y finalmente, Mainno es sorprendente que la suscripción al OnCallevento se realice llamando al add_OnCallmétodo en la Fooinstancia.
Esta es una respuesta general y refleja el comportamiento predeterminado:
Dicho esto, cada clase que proporciona eventos puede optar por implementar su evento de forma asincrónica. IDesign proporciona una clase llamada
EventsHelperque simplifica esto.[Nota] este enlace requiere que proporciones una dirección de correo electrónico para descargar la clase EventsHelper. (No estoy afiliado de ninguna manera)
fuente
Los delegados suscritos al evento se invocan sincrónicamente en el orden en que se agregaron. Si uno de los delegados lanza una excepción, no se llamará a los siguientes.
Dado que los eventos se definen con delegados de multidifusión, puede escribir su propio mecanismo de activación utilizando
e invocar a los delegados de forma asincrónica;
fuente
Los eventos son simplemente conjuntos de delegados. Siempre que la llamada de delegado sea síncrona, los eventos también lo son.
fuente
En general, los eventos son sincrónicos. Sin embargo, hay algunas excepciones, como la
System.Timers.Timer.Elapsedgeneración de un evento en unThreadPoolhilo siSyncronisingObjectes nulo.Documentos: http://msdn.microsoft.com/en-us/library/system.timers.timer.elapsed.aspx
fuente
Los eventos en C # se ejecutan sincrónicamente (en ambos casos), siempre y cuando no inicie un segundo subproceso manualmente.
fuente
Los eventos son sincrónicos. Es por eso que el ciclo de vida del evento funciona como lo hace. Los inicios ocurren antes de las cargas, las cargas ocurren antes de los renders, etc.
Si no se especifica un controlador para un evento, el ciclo simplemente se desarrolla. Si se especifica más de un controlador, se llamarán en orden y uno no puede continuar hasta que el otro haya terminado por completo.
Incluso las llamadas asincrónicas son sincrónicas hasta cierto punto. Sería imposible llamar al final antes de que se complete el comienzo.
fuente