もくじ
https://tera1707.com/entry/2022/02/06/144447#Task
やりたいこと
以前の記事で、Taskの中で例外が起きた時のキャッチの仕方を学んだが、今回、Task.WhenAll()
で複数の戻り値のあるタスクの完了を待ったときに、そのタスクのどれかで例外があったら、例外があったタスクはなにかデフォルト的な値を返し、正常に終了したタスクは通常の戻り値を返す、ということをしたい。
前提
- VisualStudio2022 ver 17.2.6
- .net6
やりかた
Taskを変数で受けておき、WhenAllをawaitしたときになにか例外が起きたら、個別のタスクを受けた変数のException
プロパティを見て、例外がないかチェックする。
→例外がなかったらタスクのResult
を返し、例外があったらデフォルト値を返す。
using System.Diagnostics; var t1 = Task<bool>.Run(() => { return true; }); var t2 = Task<string>.Run(() => { throw new ArgumentOutOfRangeException(); return "デフォ値じゃない"; }); var t3 = Task<int>.Run(() => { return 1; }); var t4 = Task<double>.Run(() => { throw new ArgumentException(); return 1.0; }); var all = Task.WhenAll(t1, t2, t3, t4); try { await all; } catch { var t1Result = GetResultFromTask(t1, false); var t2Result = GetResultFromTask(t2, "デフォ値"); var t3Result = GetResultFromTask(t3, 20); var t4Result = GetResultFromTask(t4, 30.0); Debug.WriteLine($"t1Result = {t1Result}, t2Result = {t2Result}, t3Result = {t3Result}, t4Result = {t4Result}"); } // Task実行時に // 正常終了 → Taskの戻り値を返す // 例外発生 → 指定した初期値を返す T GetResultFromTask<T>(Task<T> task, T defaultValue) { if (task.Exception is not null) { return defaultValue; } return task.Result; }
やりかた その2
例外時、自分で決めた「デフォルト値」ではなく、一般的なデフォルト値を返させるときはこうなる。
(とにかく例外時でも例外で落とさずになにか値を返すだけでいい、とかの場合はこちらの方がわかりやすいかも)
using System.Diagnostics; var t1 = Task.Run(() => { return true; }); var t2 = Task.Run(() => { throw new ArgumentOutOfRangeException(); return "デフォ値じゃない"; }); var t3 = Task.Run(() => { return 1; }); var t4 = Task.Run(() => { throw new ArgumentException(); return 1.0; }); var all = Task.WhenAll(t1, t2, t3, t4); try { await all; } catch { var t1Result = GetResultFromTask(t1); var t2Result = GetResultFromTask(t2); var t3Result = GetResultFromTask(t3); var t4Result = GetResultFromTask(t4); Debug.WriteLine($"t1Result = {t1Result}, t2Result = {t2Result ?? "nullです"}, t3Result = {t3Result}, t4Result = {t4Result}"); } // Task実行時に // 正常終了 → Taskの戻り値を返す // 例外発生 → Tに対応する初期値を返す T? GetResultFromTask<T>(Task<T> task) { if (task.Exception is not null) { return default(T); } return task.Result; }
参考
タスクの例外処理
https://blog.xin9le.net/entry/2011/08/19/222300
以前書いた、Taskの中で例外が起きた時のキャッチの仕方の記事