C#异步委托:优雅地等待异步事件
在C#中,事件传统上返回void,这使得它们与异步操作不兼容。当事件处理程序需要在通知其他组件之前执行异步任务时,就会出现这个问题。以下场景探讨了这个问题,并提供了一种使用异步委托的解决方案。
问题:
下面的代码演示了一个名为GameShuttingDown
的事件,该事件在游戏关闭时触发。每个事件处理程序都应该在游戏关闭之前异步保存数据。但是,处理程序使用void方法调用,导致游戏在保存完成之前关闭。
<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>
解决方案:
为了解决这个问题,我们可以使用返回任务的异步委托。这样,我们可以异步调用处理程序并等待结果。
将现有的GameShuttingDown
事件替换为异步委托类型:
<code class="language-csharp">public event Func<object, EventArgs, Task> GameShuttingDown;</code>
修改NotifyGameShuttingDown
方法以调用处理程序并等待其完成:
<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>
用法:
使用新的异步委托类型订阅GameShuttingDown
事件:
<code class="language-csharp">DefaultGame.GameShuttingDown += async (sender, args) => await this.repo.Save(blah);</code>
这种方法确保了游戏只有在事件处理程序中所有异步保存操作完成后才会关闭。
以上是如何使用异步委托处理 C# 中的异步事件?的详细内容。更多信息请关注PHP中文网其他相关文章!