So beantworten Sie Ihre Fragen:
- Das Auslösen eines Ereignisses blockiert den Thread, wenn die Ereignishandler alle synchron implementiert sind.
- Die Ereignishandler werden nacheinander in der Reihenfolge ausgeführt, in der sie das Ereignis abonniert haben.
Auch ich war neugierig auf den internen Mechanismus eventund die damit verbundenen Operationen. Also schrieb ich ein einfaches Programm und ildasmstöberte in seiner Implementierung herum.
Die kurze Antwort lautet
- Es gibt keine asynchrone Operation zum Abonnieren oder Aufrufen der Ereignisse.
- Das Ereignis wird mit einem Hintergrunddelegatenfeld desselben Delegatentyps implementiert
- Das Abonnieren ist abgeschlossen mit
Delegate.Combine()
- Das Abbestellen erfolgt mit
Delegate.Remove()
- Das Aufrufen erfolgt durch einfaches Aufrufen des endgültigen kombinierten Delegaten
Folgendes habe ich getan. Das Programm, das ich verwendet habe:
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();
}
}
Hier ist die Implementierung von Foo:

Beachten Sie, dass es ein Feld OnCall und ein Ereignis gibt OnCall . Das Feld OnCallist offensichtlich die Backing-Eigenschaft. Und es ist nur ein Func<int, string>, nichts Besonderes hier.
Nun sind die interessanten Teile:
add_OnCall(Func<int, string>)
remove_OnCall(Func<int, string>)
- und wie
OnCallwird in aufgerufenDo()
Wie wird das Abonnieren und Abbestellen implementiert?
Hier ist die abgekürzte add_OnCallImplementierung in CIL. Der interessante Teil ist, dass Delegate.Combinezwei Delegaten verkettet werden.
.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
Ebenso Delegate.Removewird in verwendet remove_OnCall.
Wie wird ein Ereignis aufgerufen?
Zum Aufrufen OnCallin Do(), ruft er einfach die letzte verkettete Delegierten nach dem ARG - Laden:
IL_0026: callvirt instance !1 class [mscorlib]System.Func`2<int32,string>::Invoke(!0)
Wie genau abonniert ein Abonnent eine Veranstaltung?
Und schließlich Mainerfolgt das Abonnieren des OnCallEreignisses , nicht überraschend, durch Aufrufen der add_OnCallMethode für die FooInstanz.