21

失敗したタスク (例外が設定されているタスク)awaitを待機しているときに、格納されている例外を再スローします。保存された例外が の場合AggregateException、最初の例外が再スローされ、残りは破棄されます。

エラー情報を誤って失わないように、どのように使用するawaitと同時にオリジナルをスローすることができますか?AggregateException

もちろん、これに対するハックな解決策を考えることが可能であることに注意してください (たとえば、 を try-catch してawaitから を呼び出しますTask.Wait)。私は本当にきれいな解決策を見つけたいと思っています。ここでのベストプラクティスは何ですか?

カスタム awaiter を使用することを考えましたが、ビルトインにTaskAwaiterは多くの魔法が含まれており、完全に再現する方法がわかりません。TPL 型で内部 API を呼び出します。また、そのすべてを再現したくありません。

あなたがそれで遊んでみたいなら、ここに短い再現があります:

static void Main()
{
    Run().Wait();
}

static async Task Run()
{
    Task[] tasks = new[] { CreateTask("ex1"), CreateTask("ex2") };
    await Task.WhenAll(tasks);
}

static Task CreateTask(string message)
{
    return Task.Factory.StartNew(() => { throw new Exception(message); });
}

では、2 つの例外のうち 1 つだけがスローされRunます。

Stack Overflow に関する他の質問では、この特定の問題に対処していないことに注意してください。重複を提案するときは注意してください。

4

6 に答える 6

24

awaitの動作が望ましくないという質問のタイトルの意味には同意しません。これは、ほとんどのシナリオで理にかなっています。あるWhenAll状況で、 1 つだけではなく、すべてのエラーの詳細を本当に知る必要がある頻度はどれくらいですか?

主な問題AggregateExceptionは例外処理です。つまり、特定の型をキャッチできなくなります。

つまり、拡張メソッドを使用して必要な動作を取得できます。

public static async Task WithAggregateException(this Task source)
{
  try
  {
    await source.ConfigureAwait(false);
  }
  catch
  {
    // source.Exception may be null if the task was canceled.
    if (source.Exception == null)
      throw;

    // EDI preserves the original exception's stack trace, if any.
    ExceptionDispatchInfo.Capture(source.Exception).Throw();
  }
}
于 2013-08-19T13:56:25.237 に答える
3

例外処理 (タスク並列ライブラリ)

私はもっ​​と言うことができますが、それはただのパディングです. 彼らが言うように、それはうまくいきます。ただ注意が必要です。

多分あなたはこれが欲しい

神 (Jon Skeet) が await 例外処理について説明

(個人的には await を敬遠しますが、それは私の好みです)

コメントへの返信 (コメント返信には長すぎます)

次に、同様の議論の出発点としてスレッドを使用します。これは、ベスト プラクティスのソースがここにあるためです。

例外を渡すコードを実装しない限り、例外は喜んで飲み込まれます (たとえば、await がおそらくラップしている非同期パターン... イベントを発生させるときにイベント args オブジェクトに例外を追加します)。任意の数のスレッドを起動して実行するシナリオがある場合、順序や各スレッドを終了するポイントを制御することはできません。さらに、あるエラーが別のエラーに関連している場合、このパターンを使用することはありません。したがって、残りの実行が完全に独立していることを強く暗示しています-IEは強くこれらのスレッドの例外は、すでに例外として処理されていることを意味します。これらのスレッドで発生するスレッドで例外を処理する以上のことをしたい場合 (これは奇妙です)、参照によって渡されるロック コレクションに例外を追加する必要があります。情報 - 並行バッグを使用し、例外を、それが由来するコンテキストを識別するために必要な情報にラップします - これはそれに渡されます。

ユースケースを混同しないでください。

于 2013-08-19T13:50:22.020 に答える