2011-07-13 17 views
2

非同期デリゲートコールから未処理の例外をキャッチしようとしています。次のプログラムは、この問題を示しています。私は、次のような出力が得られます。非同期デリゲートコールで未処理の例外が発生しました

Delegate called. 
Unhandled exception: an exception. 

または

Delegate called. 
EndInvoke() threw an exception: an exception. 
Program ended. 

または

Delegate called. 
EndInvoke() threw an exception: an exception. 
Program ended. 
Unhandled exception: an exception. 

異なる結果が同期の問題に起因するものです。コールを修正するには?

using System; 

namespace AsyncCallback 
{ 
    public delegate void SampleDelegate(); 

    public class Program 
    { 
     private static SampleDelegate sampleDelegate; 

     public static void Main(string[] args) 
     { 
      AppDomain.CurrentDomain.UnhandledException += UnhandledException; 

      sampleDelegate = ThrowException; 
      var result = sampleDelegate.BeginInvoke(Callback, null); 

      Console.WriteLine("Delegate called."); 

      result.AsyncWaitHandle.WaitOne(); 

      Console.WriteLine("Program ended."); 
     } 

     private static void Callback(IAsyncResult result) 
     { 
      try 
      { 
       sampleDelegate.EndInvoke(result); 
       Console.WriteLine("EndInvoke() completed."); 
      } 
      catch (Exception ex) 
      { 
       Console.WriteLine("EndInvoke() threw an exception: {0}.", ex.Message); 
       throw; 
      } 
     } 

     private static void UnhandledException(object sender, UnhandledExceptionEventArgs e) 
     { 
      Console.WriteLine("Unhandled exception: {0}.", (e.ExceptionObject as Exception).Message); 
     } 

     private static void ThrowException() 
     { 
      throw new Exception("an exception"); 
     } 
    } 
} 
+0

あなたは何をしたいですか? 'EndInvoke()'から例外を正しく捕捉しています。なぜあなたはそれを再投げているのですか? –

+0

このプログラムには暗黙のレースがあります。 WaitOne()コールはthrowステートメントと競合しています。これにより、処理されない例外が発生してプロセスがシャットダウンされます。これは、メインスレッドがWaitOne呼び出しを過ぎる前に起きても、起きなくてもよい。このレースを修正しようとするのはあまり意味がありません。プロセスはいずれにせよ死んでいます。 –

+0

@Cory Nelson:メッセージが印刷されるかどうかは決定的ではないため、これを正しく実行していないように見えます。私はその例外を記録する必要があります。再開は未処理の例外をシミュレートしています。 – Stefan

答えて

2

デリゲートを非同期に呼び出す場合、2つのオプションがあります。

オプション1:コールバックなし。私はこれがあなたがやろうとしていることだと思う。

SomeDelegate d; 

IAsyncResult res = d.BeginInvoke(null, null); 

//..do some other work in the meantime. 

try 
{ 
    // EndInvoke will wait until execution completes. 
    // WaitHandle use not needed! 
    d.EndInvoke(res); 
} 
catch(Exception ex) 
{ 
    // 
} 

オプション2:コールバック。

SomeDelegate d; 

d.BeginInvoke(res => 
{ 
    // this is called once the delegate completes execution. 

    try 
    { 
     d.EndInvoke(res); 
    } 
    catch(Exception ex) 
    { 
     // 
    } 
}, null); 

//..do some other work in the meantime. 

// everything pertaining to the delegate's completion is done in the callback. 
// no exception handling should be done here. 

どちらのフォームを使用しているかは、どちらが正しいかによって異なります。彼らはあなたがしたように、通常は結合されていません。

+0

私がしようとしているのは2番目のオプションですが、try/catchブロックはありません。例外をAppDomain.CurrentDomain.UnhandledExceptionハンドラで処理しないようにします。 – Stefan

関連する問題