6

タスクを返すAsyncメソッドがあります。非同期の観点から同期メソッドを実装するためのパターン(翻訳/アンラッピングAggregateExceptions)

私はまた、同等の同期を提供したいと思いますが、コンシューマには開梱する必要はありませんAggregateException s。

私はあなたが一般的な方法で任意に1つを選ぶことができないということを理解しています。そして、私はもっと読み込んでいくことができます。もっとスティーブントゥブの記事(私はそうですが、今はありません)それはすべて、自分のために決めることができます。

中間では、私の仕事は実際には、複数の例外をもたらしてはならないWaits(no、TPL DataFlowではなく)だけで、並列性のない「ワークフロー」にちょうどチェーンされているという事実を利用したい。その場合には、次のように扱うことが適切であろう:

CallAsync().Wait(); 
} 
catch(AggregateException ae) 
{ 
    throw ae.Flatten().First() 

をか私はAggregateExceptionは、常に複数ある場合でも、InnerExceptionを持っていることを保証しています。または、私が.Flatten().First()に落ちなければならない場合はありますか?いくつかのTPLドキュメントで


、私は(それがベータリリースで拡張か何かだったかどうかわからない)AggregateExceptionUnwrap()メソッドへの参照を参照してください。プレースホルダとして

、私がやっている:

void Call() 
{ 
    try 
    { 
     CallAsync().Wait(); 
    } 
    catch (AggregateException ex) 
    { 
     var translated = ex.InnerException ?? ex.Flatten().InnerExceptions.First(); 
     if (translated == null) 
      throw; 
     throw translated;     } 
} 

Task CallAsync(){ ... 

答えて

21

を私が知っているこれを行うには、「クリーン」方法はありません。 throw someInnerException;を使用することはできません。これは、非同期ワークフローで例外が発生した場所でスタックを失うためです。throw;を使用している場合は、明らかにAggregateExceptionを伝播します。同期メソッドのために何をしなければならないかは、AggregateExceptionの最初の例外を埋めることができ、そのメソッドの同期バージョンから一貫してスローすることができる「ラッパー」例外があります。

void Call() 
{ 
    try 
    { 
     CallAsync().Wait(); 
    } 
    catch (AggregateException ex) 
    { 
     throw new MyConsistentWrapperException("An exception occurred while executing my workflow. Check the inner exception for more details.", ex.Flatten().InnerExceptions.First()); 
    } 
} 

FWIWは、彼らはあなたがスタックを打つことなく、スレッド間の例外をマーシャリングするのに役立ちますthe new ExceptionDispatchInfo classと4.5でこれを解決してきました。次に、このような同期バージョンを書くことができます:

void Call() 
{ 
    try 
    { 
     CallAsync().Wait(); 
    } 
    catch (AggregateException ex) 
    { 
     ExceptionDispatchInfo.Capture(ex.Flatten().InnerExceptions.First()).Throw(); 
    } 
} 
+1

ありがとう;特に私が考えていたスタックの損失点のために、(私は中程度の信頼に基づいているので、通常のPreserveStackTraceトリックが機能するかどうか分からずに試してみてください)。最終的な質問ですが(実際の出発点) - ほとんどのサンプルが '.Flatten()。InnerExceptions.First()'やその他のアンラッピング方法の代わりに '.InnerException'を使用する理由は同じですか? **?もしそうなら、どんな参考文献ですか?アンラッピングの方法は他にありますか? –

+0

ILDasmでAggregateExceptionコンストラクタを見れば、他の実装によって委譲された(string、IList )のプライベートコンストラクタが最終的にあることがわかりますそのコンストラクタでは、IList の最初の例外をinnerExceptionパラメータとして渡して、ベースの例外コンストラクタを呼び出します。しかし、最初の例外は技術的に別のAggregateExceptionになる可能性があるため、Flatten()を使用することは、基礎となる最初の非AggregateException例外を取得するための保証された方法です。 –

+0

それは完璧に説明されています。私は、50ページのドキュメントと記事のうちの1つが、それをsuccintlyとして説明できることを願っています。 (私はTPLでまだデコンパイラを持っていません - 何らかの理由で私はそれを精神的に限界から除外します。私がWCFにその態度を取らないように説明する方法は...:D) –

関連する問題