Per rispondere alle tue domande:
- La generazione di un evento blocca il thread se i gestori di eventi sono tutti implementati in modo sincrono.
- I gestori di eventi vengono eseguiti in sequenza, uno dopo l'altro, nell'ordine in cui sono iscritti all'evento.
Anch'io ero curioso del meccanismo interno di evente delle sue operazioni correlate. Quindi ho scritto un semplice programma e ne ho ildasmcurati l'implementazione.
La risposta breve è
- non ci sono operazioni asincrone coinvolte nella sottoscrizione o nel richiamo degli eventi.
- L'evento viene implementato con un campo delegato di supporto dello stesso tipo di delegato
- l'iscrizione è terminata con
Delegate.Combine()
- l'annullamento dell'iscrizione è fatto con
Delegate.Remove()
- La chiamata viene eseguita semplicemente invocando il delegato combinato finale
Ecco cosa ho fatto. Il programma che ho usato:
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();
}
}
Ecco l'implementazione di Foo:

Nota che sono presenti un campo OnCall e un evento OnCall . Il campo OnCallè ovviamente la proprietà di supporto. Ed è semplicemente un fileFunc<int, string> , niente di speciale qui.
Ora le parti interessanti sono:
add_OnCall(Func<int, string>)
remove_OnCall(Func<int, string>)
- e come
OnCallviene invocato inDo()
Come vengono implementate la sottoscrizione e l'annullamento della sottoscrizione?
Ecco l' add_OnCallimplementazione abbreviata in CIL. La parte interessante è che utilizza Delegate.Combineper concatenare due delegati.
.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
Allo stesso modo, Delegate.Removeviene utilizzato in remove_OnCall.
Come viene invocato un evento?
Per richiamare OnCallin Do(), si chiama semplicemente il delegato concatenato finale dopo aver caricato l'arg:
IL_0026: callvirt instance !1 class [mscorlib]System.Func`2<int32,string>::Invoke(!0)
In che modo esattamente un abbonato si iscrive a un evento?
Infine, Mainnon sorprendentemente, la sottoscrizione OnCallall'evento viene eseguita chiamando il add_OnCallmetodo Foosull'istanza.