C#异步事件处理详解
引言
C#事件机制是处理异步操作的强大工具。然而,传统的事件是无返回值的(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() { // ... }</code>
问题在于,NotifyGameShuttingDown
事件处理程序是无返回值的,在ShutdownGame
方法中调用它会阻止异步保存任务在事件触发之前完成。
解决方案一:自定义异步事件委托
一种方法是定义一个返回Task的自定义事件委托,允许等待处理程序的执行:
<code class="language-csharp">public event Func<object, EventArgs, Task> Shutdown;</code>
在ShutdownGame
方法中,处理程序可以这样调用:
<code class="language-csharp">Func<object, EventArgs, Task> handler = Shutdown; 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>
解决方案二:基于注册的方法
另一种选择是使用基于注册的方法,其中可以异步注册和执行回调:
<code class="language-csharp">private List<Func<Task>> ShutdownCallbacks = new List<Func<Task>>(); public void RegisterShutdownCallback(Func<Task> callback) { this.ShutdownCallbacks.Add(callback); } public async Task Shutdown() { var callbackTasks = new List<Task>(); foreach (var callback in this.ShutdownCallbacks) { callbackTasks.Add(callback()); } await Task.WhenAll(callbackTasks); }</code>
注意事项
推荐
推荐的方法取决于应用程序的具体需求。对于现有代码库以及大量基于事件的设计,自定义委托方法是首选。对于新的应用程序或那些不依赖于事件的应用程序,基于注册的方法可以提供更好的性能和灵活性。
以上是如何在 C# 中处理异步事件?的详细内容。更多信息请关注PHP中文网其他相关文章!