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 中国語 Web サイトの他の関連記事を参照してください。