Die Cerating Extention-Methode, wie sie vorgeschlagen wurde, löst Probleme mit den Rennbedingungen nicht wirklich, sondern verbirgt sie.
public static void SafeInvoke(this EventHandler handler, object sender)
{
if (handler != null) handler(sender, EventArgs.Empty);
}
Wie bereits erwähnt, ist dieser Code das elegante Äquivalent zur Lösung mit temporärer Variable, aber ...
Das Problem bei beiden ist, dass es möglich ist, dass der Subsciber des Ereignisses aufgerufen wird, nachdem er sich vom Ereignis abgemeldet hat . Dies ist möglich, da die Abmeldung erfolgen kann, nachdem die Delegateninstanz in die temporäre Variable kopiert (oder in der obigen Methode als Parameter übergeben) wurde, jedoch bevor der Delegat aufgerufen wird.
Im Allgemeinen ist das Verhalten des Client-Codes in einem solchen Fall nicht vorhersehbar: Der Komponentenstatus konnte die Ereignisbenachrichtigung nicht bereits verarbeiten. Es ist möglich, Client-Code so zu schreiben, dass er damit umgeht, aber dies würde dem Client unnötige Verantwortung auferlegen.
Die einzige bekannte Möglichkeit, die Thread-Sicherheit zu gewährleisten, ist die Verwendung der Lock-Anweisung für den Absender des Ereignisses. Dadurch wird sichergestellt, dass alle Abonnements \ Abmeldungen \ Aufruf serialisiert werden.
Um genauer zu sein, sollte die Sperre auf dasselbe Synchronisierungsobjekt angewendet werden, das in den Methoden zum Hinzufügen / Entfernen von Ereigniszugriff verwendet wird. Dies ist die Standardeinstellung 'this'.