Asynchroner C#-Delegat: Warten Sie elegant auf asynchrone Ereignisse
In C# geben Ereignisse traditionell „void“ zurück, was sie mit asynchronen Vorgängen inkompatibel macht. Dieses Problem tritt auf, wenn ein Ereignishandler eine asynchrone Aufgabe ausführen muss, bevor er andere Komponenten benachrichtigt. Das folgende Szenario untersucht dieses Problem und bietet eine Lösung mithilfe eines asynchronen Delegaten.
Frage:
Der folgende Code zeigt ein Ereignis namens GameShuttingDown
, das ausgelöst wird, wenn das Spiel geschlossen wird. Jeder Event-Handler sollte Daten asynchron speichern, bevor das Spiel geschlossen wird. Allerdings wird der Handler mit einer void-Methode aufgerufen, was dazu führt, dass das Spiel geschlossen wird, bevor der Speichervorgang abgeschlossen ist.
<code class="language-csharp">public event EventHandler<EventArgs> GameShuttingDown; public async Task ShutdownGame() { await this.NotifyGameShuttingDown(); await this.SaveWorlds(); this.NotifyGameShutDown(); } private async Task SaveWorlds() { foreach (DefaultWorld world in this.Worlds) { await this.worldService.SaveWorld(world); } } protected virtual void NotifyGameShuttingDown() { var handler = this.GameShuttingDown; if (handler == null) { return; } handler(this, new EventArgs()); }</code>
Lösung:
Um dieses Problem zu lösen, können wir einen asynchronen Delegaten verwenden, der eine Aufgabe zurückgibt. Auf diese Weise können wir den Handler asynchron aufrufen und auf das Ergebnis warten.
Ersetzen Sie das vorhandene GameShuttingDown
-Ereignis durch einen asynchronen Delegatentyp:
<code class="language-csharp">public event Func<object, EventArgs, Task> GameShuttingDown;</code>
Ändern Sie die Methode NotifyGameShuttingDown
, um den Handler aufzurufen, und warten Sie, bis der Vorgang abgeschlossen ist:
<code class="language-csharp">protected virtual async Task NotifyGameShuttingDown() { Func<object, EventArgs, Task> handler = GameShuttingDown; if (handler == null) { return; } Delegate[] invocationList = handler.GetInvocationList(); Task[] handlerTasks = new Task[invocationList.Length]; for (int i = 0; i < invocationList.Length; i++) { handlerTasks[i] = ((Func<object, EventArgs, Task>)invocationList[i])(this, EventArgs.Empty); } await Task.WhenAll(handlerTasks); }</code>
Verwendung:
Abonnieren Sie GameShuttingDown
Ereignisse mit dem neuen asynchronen Delegatentyp:
<code class="language-csharp">DefaultGame.GameShuttingDown += async (sender, args) => await this.repo.Save(blah);</code>
Dieser Ansatz stellt sicher, dass das Spiel erst geschlossen wird, nachdem alle asynchronen Speichervorgänge im Event-Handler abgeschlossen wurden.
Das obige ist der detaillierte Inhalt vonWie behandelt man asynchrone Ereignisse in C# mithilfe von asynchronen Delegaten?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!