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