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中文網其他相關文章!