2016-04-06 11 views
0

私はprogram.csでいくつかの "グローバル"例外処理を設定したWinForm非同期GUIアプリケーションを持っています。私はまた、 "待っているTask.WhenAll()"を実行し、その例外をキャッチし、待っているTask.Exceptionプロパティを投げるGUIスレッドを持っているので、AggregateExceptionはprogram.cs内の例外ハンドラに至るまで得られる(私はしたい内側の例外を反復処理してログに記録する)。GUIスレッドからスローされたAggregateExceptionがアプリ例外ハンドラで「アンラップ」するのはなぜですか?

WhenAll()のtry/catchからスローされた例外が実際にAggreateExceptionをスローしているのがわかりますが、program.csのハンドラをデバッグするとAggregateExceptionはもうありません。 AggregateExceptionの例外。私はこのコードを「アンラッピング」しているのか分かりません。

のProgram.cs:Form1.csの

private async void button1_Click(object sender, EventArgs e) { 

      Task overall = Task.WhenAll(
       Task.Run(()=> { throw new ApplicationException("message 1"); }), 
       Task.Run(() => { throw new ApplicationException("message 2"); }) 
       ); 

      try { 
       await overall; 
       } 
      catch { 
       throw overall.Exception; // this is AggregateException 
       } 
      } 
     } 
+1

グローバル例外処理をキャッチされない例外のためにそこにあることを。あなたが*例外*を期待するならば、それが捕らえられないようにしてください。いずれにせよ、私はあなたが望むなら、あなた自身の例外で 'AggregateException'をラップすることができると思います。 – Luaan

+0

@MichaelRayLovett:再現性のある最小限の例を投稿できますか? –

+0

AggregateExceptionをスローする理由はありません。その例外は、非同期メソッド内で発生した1つ以上の例外に対するラッパーです。 'await' *は最初の内部例外を返します。私はそこに 'waitAll();'があると思って、最初の例外がUIスレッドで再スクロールされるのを疑う。 –

答えて

2

static void Main() { 
    Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException); 
    Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); 
    ... 
    } 

static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { 
      if (e.Exception is AggregateException) { 
       // expect to log the contents of (e.Exception as AggregateException).Flatten().InnerExceptions, but exception coming 
       // in is not AggregateException but instead is 
       // ApplicationException("message 1") 
       } 
      else { 
       // handling for non aggregate exceptions 
       } 

それはちょうどAggregateExceptionない - のWinFormsは常にのみハンドラにGetBaseException()を送信します。つまり、InnerExceptionチェーンの最も内側の例外のみです。

明らかに、これはlongstanding WinForms bugで、おそらくこの時点では永久です。

あなたはあなた自身のタイプでそれを回避する必要があります:

public class ExceptionWrapper : Exception 
{ 
    public new Exception InnerException { get; set; } 
} 

throw new ExceptionWrapper { InnerException = overall.Exception }; 
+0

うわー、それは本のためのものです。私は「感謝」と言うべきではないと知っていますが、「感謝」です:) –

0

this issueための最善の回避策はAppDomain.FirstChangeExceptionイベントを経由して発生した例外を捕捉し、その後、例外に対してこの例外の基本例外への参照を比較しています上昇したのはApplication.ThreadExceptionです。このような

何か:

private Exception lastFirstChanceException; 
AppDomain.CurrentDomain.FirstChanceException += (sender, e) => 
{ 
    lastFirstChanceException = e.Exception; 
}; 
Application.ThreadException += (sender, e) => 
{ 
    if (lastFirstChanceException?.GetBaseException() == e.Exception) 
    { 
     var realException = lastFirstChanceException; // This is the "real" exception thrown by some code 
    } 
}; 
関連する問題