Délégué asynchrone C# : attendez gracieusement les événements asynchrones
En C#, les événements renvoient traditionnellement void, ce qui les rend incompatibles avec les opérations asynchrones. Ce problème survient lorsqu'un gestionnaire d'événements doit effectuer une tâche asynchrone avant d'en informer d'autres composants. Le scénario suivant explore ce problème et fournit une solution à l’aide d’un délégué asynchrone.
Question :
Le code ci-dessous montre un événement nommé GameShuttingDown
qui se déclenche lorsque le jeu est fermé. Chaque gestionnaire d'événements doit sauvegarder les données de manière asynchrone avant la fermeture du jeu. Cependant, le gestionnaire est appelé avec une méthode void, provoquant la fermeture du jeu avant la fin de la sauvegarde.
<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>
Solution :
Pour résoudre ce problème, nous pouvons utiliser un délégué asynchrone qui renvoie une tâche. De cette façon, nous pouvons appeler le gestionnaire de manière asynchrone et attendre le résultat.
Remplacez l'événement GameShuttingDown
existant par un type de délégué asynchrone :
<code class="language-csharp">public event Func<object, EventArgs, Task> GameShuttingDown;</code>
Modifiez la méthode NotifyGameShuttingDown
pour appeler le gestionnaire et attendez qu'elle se termine :
<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>
Utilisation :
Abonnez-vous aux événements GameShuttingDown
en utilisant le nouveau type de délégué asynchrone :
<code class="language-csharp">DefaultGame.GameShuttingDown += async (sender, args) => await this.repo.Save(blah);</code>
Cette approche garantit que le jeu ne se fermera qu'une fois toutes les opérations de sauvegarde asynchrones dans le gestionnaire d'événements terminées.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!