处理C#中的异步事件:安全地等待异步操作
问题概述:
在C#中,事件通常是无返回值的委托,用于通知应用程序中特定事件的订阅者。然而,当尝试使用异步事件处理程序时,可能会出现一个问题:事件被触发,而异步处理程序完成执行之前,应用程序就关闭了。
使用异步处理程序订阅事件:
为了异步处理事件,不建议修改事件签名本身以返回Task。相反,您可以使用一个注册方法,该方法接受一个可等待的回调函数。这样可以提供更大的灵活性和更轻松地与第三方组件集成。
使用注册方法的实现:
<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>
在此示例中,ShutdownCallbacks
列表存储可等待的回调函数。Shutdown()
方法迭代这些回调函数并同时等待它们。这确保了在关闭过程继续之前,所有异步处理程序都已完成。
使用调用列表调用事件:
或者,如果您希望保留现有的事件范例,可以使用 GetInvocationList()
方法顺序调用处理程序并等待返回的 Tasks。
<code class="language-csharp">class A { public event Func<object, EventArgs, Task> Shutdown; public async Task OnShutdown() { 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>
在这里,OnShutdown()
获取事件委托,调用处理程序并等待它们的完成。
结论:
虽然异步事件处理程序看起来很诱人,但由于可能出现死锁和其他问题,通常不建议使用这种方法。如上所述,使用注册方法或调用列表为在 C# 中异步等待事件提供了一种更健壮且更易于管理的解决方案。
以上是如何在 C# 中安全地等待异步事件?的详细内容。更多信息请关注PHP中文网其他相关文章!