C#非同步事件的優雅處理方法
在C#應用程式中,如果一個類別包含事件(例如'GameShuttingDown'事件),而事件處理程序是非同步的,可能會出現遊戲在等待的事件處理程序完成之前就關閉的問題。這是因為事件本身是同步的,而處理程序卻是非同步的。
雖然可以使用非同步機制來取代事件,但這會損失事件的簡潔性。更好的方法是保持事件的表達能力,同時實現非同步處理。 我們可以透過自訂委託類型,而非使用標準的EventHandler
來實現。
以下範例顯示如何實現:
<code class="language-csharp">public class A { public event Func<object, EventArgs, Task> Shutdown; public async Task OnShutdown() { var handler = Shutdown; if (handler == null) { return; } var invocationList = handler.GetInvocationList(); var handlerTasks = invocationList.Select(h => ((Func<object, EventArgs, Task>)h)(this, EventArgs.Empty)).ToArray(); await Task.WhenAll(handlerTasks); } }</code>
在OnShutdown()
方法中,我們先取得事件委託的本地副本。然後,我們呼叫所有處理程序,並將傳回的任務儲存在一個陣列中。最後,我們使用Task.WhenAll()
等待所有任務完成。 這比循環迭代更簡潔。
以下是一個簡單的控制台程序,演示了使用方法:
<code class="language-csharp">public class Program { public static void Main(string[] args) { var a = new A(); a.Shutdown += Handler1; a.Shutdown += Handler2; a.Shutdown += Handler3; a.OnShutdown().Wait(); } public static async Task Handler1(object sender, EventArgs e) { Console.WriteLine("启动关闭处理程序 #1"); await Task.Delay(1000); Console.WriteLine("关闭处理程序 #1 完成"); } public static async Task Handler2(object sender, EventArgs e) { Console.WriteLine("启动关闭处理程序 #2"); await Task.Delay(5000); Console.WriteLine("关闭处理程序 #2 完成"); } public static async Task Handler3(object sender, EventArgs e) { Console.WriteLine("启动关闭处理程序 #3"); await Task.Delay(2000); Console.WriteLine("关闭处理程序 #3 完成"); } }</code>
這種方法保留了事件的簡潔性,同時確保處理程序非同步執行,避免了同步阻塞問題。 使用LINQ的Select
方法簡化了程式碼,使其更易於閱讀和維護。
以上是如何使 C# 事件異步?的詳細內容。更多資訊請關注PHP中文網其他相關文章!