つい先日、C#で非同期処理を簡潔に書ける async
, await
を使った処理の例外処理でハマった。。。
具体的には、async
で書いた非同期処理でも、wait
で待ち合わせてを行った以降は、非同期処理内で発生した例外はすべて AggregateException
にラップされるという話だ。
スポンサーリンク
async / await の例外処理の基本
async / await は、非同期の処理を同期処理かのように書けるようにしたC#の構文であるため、例外処理についても、特に意識せずに発生した例外を try ~ catch
でハンドリングすることが可能である。
例えば、次のようなコードの場合、非同期処理である DoAsyncTask
メソッド内で発生した ApplicationException
は、呼び出し元で普通に try ~ catch
で ApplicationException
をハンドリングすればキャッチ可能である。
public static async Task Sample() {
try {
await DoAsyncTask();
} catch (ApplicationException) {
Console.WriteLine("ApplicationExceptionが発生");
} catch (Exception ex) {
Console.WriteLine("その他の例外が発生 " + ex.GetType().Name);
}
}
public static async Task DoAsyncTask() {
// 非同期的な処理
await Task.Delay(1000);
// 例外を発生される
throw new ApplicationException();
}
■ 実行結果
ApplicationExceptionが発生
スポンサーリンク
waitで待ち合わせするとAggregateExceptionが発生
Task#wait
メソッドは、指定した Task の処理が完了するまで待機するメソッドである。
今回ハマったのが、 async
, await
で非同期処理を書いていたとしても、Task#wait
で処理を待ち合わせすると、それ以降に発生する例外は、すべて AggregateException
にラップされたスローされることである。(まぁ当然と言えば当然ですが。。。)
public static void Sample() {
try {
DoAsyncTask().Wait(); //ここで wait()を呼ぶと、非同期処理で発生する例外は AggregateExceptionになる
} catch (ApplicationException) {
Console.WriteLine("ApplicationExceptionが発生");
} catch (Exception ex) {
Console.WriteLine("その他の例外が発生 " + ex.GetType().Name);
}
}
public static async Task DoAsyncTask() {
// 非同期的な処理
await Task.Delay(1000);
// 例外を発生される
throw new ApplicationException();
}
■ 実行結果
その他の例外が発生 AggregateException
分かってみれば単純な問題ではあるが、元々 async
, await
だけで作っていた処理に、Task#wait
などで待ち合わせ処理を入れるように改修してしまうと、それ以降の try ~ catch
を見直す必要がある点が、以外と漏れてしまうので注意が必要だ。
0 件のコメント:
コメントを投稿