2011-07-13 97 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

當異步調用委託時,您有兩個選項。

選項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

我想要做的是第二個選項,但沒有try/catch塊。我想通過AppDomain.CurrentDomain.UnhandledException處理程序來處理異常。 – Stefan