単発タスク(Task.WaitAllとかで集約していないタスク)を使った非同期処理を扱うメソッドでの例外を投げる場合、 AggregateException をそのまま出すと、メソッドを呼ぶ側で InnerException をチェックしたりしないといけないので面倒です(面倒ですよね?)。
/// <exception cref="AggregateException">非同期処理がIOExceptionした場合. InnerException参照のこと</exception> void hoge() { Task t = Task.Run(() => { // ※ 裏で進められる IOException が出るかもしれない処理 }); // ※ 表の処理 t.Wait(); // AggregateException 出るかも } try { hoge(); } catch (AggregateException e) { if (e.InnerException is IOException) { // IOException の処理 } }
InnerException を throw するとスタックトレースが破棄されて(デバッグ時に)使い物にならない。
/// <exception cref="IOException">IOException出た</exception> void hoge() { Task t = Task.Run(() => { // ※ 裏で進める IOException が出るかもしれない処理 }); // ※ 表の処理 try { t.Wait(); // AggregateException 出るかも } catch (AggregateException e) { throw e.InnerException; } } try { hoge(); } catch (IOException e) { // IOException の処理 // ※ e のスタックトレースは throw e.InnerException 時点なので… }
なので、 .Net 4.5 以降に制限されますが、 ExceptionDispatchInfo.Capture を使ってスタックトレースを保ったまま InnerException を throw しましょう。
呼び出し元では IOException 待つだけなので少し幸せに。
/// <exception cref="IOException">IOException出た</exception> void hoge() { Task t = Task.Run(() => { // ※ 裏で進める IOException が出るかもしれない処理 }); // ※ 表の処理 try { t.Wait(); // AggregateException 出るかも } catch (AggregateException e) { ExceptionDispatchInfo.Capture(e.InnerException).Throw(); // スタックトレースを保って InnerException を throw } } try { hoge(); } catch (IOException e) { // IOException の処理 // ※ e のスタックトレースは Task 内での例外発生時点 デバッグが楽に }
await を使えるなら await でよさそうですが、タスクのタイムアウト待ちしたりする場合や async にしたくない場合には使えないので。
.net - In C#, how can I rethrow InnerException without losing stack trace? - Stack Overflow