14

継続チェーンで例外を伝播する適切な方法は何ですか?

t.ContinueWith(t2 => 
{
     if(t2.Exception != null)
         throw t2.Exception;

     /* Other async code. */
})
.ContinueWith(/*...*/);   

t.ContinueWith(t2 => 
{
     if(t2.IsFaulted)
         throw t2.Exception;

     /* Other async code. */
})
.ContinueWith(/*...*/);

t.ContinueWith(t2 => 
{
     if(t2.Exception != null)
         return t2;

     /* Other async code. */
})
.ContinueWith(/*...*/);   

t.ContinueWith(t2 => 
{
     if(t2.IsFaulted)
         return t2;

     /* Other async code. */
})
.ContinueWith(/*...*/);


t.ContinueWith(t2 => 
{
     t2.Wait();

     /* Other async code. */
})
.ContinueWith(/*...*/);

t.ContinueWith(t2 => 
{     
     /* Other async code. */
}, TaskContinuationOptions.NotOnFaulted) // Don't think this one works as expected
.ContinueWith(/*...*/);
4

4 に答える 4

4

条件が満たされない場合TaskContinuationOptions.OnlyOn...、継続がキャンセルされるため、問題が発生する可能性があります。これを理解する前に、書いたコードにいくつかの微妙な問題がありました。

このような連鎖した継続は、実際には正しく行うのが非常に困難です。 最も簡単な修正は、新しい .NET 4.5await機能を使用することです。これにより、非同期コードを書いているという事実をほとんど無視することができます。同期ブロックと同じように、try/catch ブロックを使用できます。.NET 4 の場合、これはasync ターゲット パックを使用して利用できます。

.NET 4.0 を使用している場合、最も簡単な方法はTask.Result、各継続の先行タスクからアクセスすることです。結果が返されないTask.Wait()場合は、サンプル コードで行っているように使用します。ただし、オブジェクトのネストされたツリーになる可能性が高くAggregateException、「実際の」例外に到達するために後で解明する必要があります。(繰り返しになりますが、.NET 4.5 ではこれがより簡単になります。while Task.ResultthrowsはAggregateExceptionTask.GetAwaiter().GetResult()それ以外は同等ですが、基になる例外をスローします。)

これは実際には些細な問題ではないことを繰り返しますが、C# 5 非同期コードでの例外処理に関する Eric Lippert の記事 (こちらこちら) に興味があるかもしれません。

于 2014-03-13T16:11:47.757 に答える
1

例外が発生した場合 (つまりログ記録) に特に何もしたくなく、単に例外を伝播させたい場合は、例外がスローされたとき (またはキャンセルの場合) に継続を実行しないでください。

task.ContinueWith(t =>
{
    //do stuff
}, TaskContinuationOptions.OnlyOnRanToCompletion);

例外のケースを明示的に処理したい場合 (おそらくログを記録するために、スローされた例外を他のタイプの例外に変更します (おそらく追加情報を含むか、公開してはならない情報を曖昧にするため))、追加できますオプションによる継続OnlyOnFaulted(おそらく通常の継続に加えて)。

于 2013-03-18T17:47:12.530 に答える
0

このオプションは、以前のタスクが正しく実行できなかっOnlyOnFaultedた場合に備えています。Task1 つの方法は、すべての継続タスクで例外を再スローすることですが、それは悪い設計です。

通常のオブジェクトと同じように例外を渡したい場合は、それを 1 つとして扱います。例外Taskを返してTask.Result、継続でプロパティを使用します。

于 2014-03-10T22:13:57.233 に答える