2011-05-12 49 views
83

我的方法之一(Method1)產生了一個新的線程。 該線程執行一個方法(Method2),並在執行過程中引發異常。 我需要的調用方法是異常信息(Method1捕捉異常拋出不同的線程

有什麼方法我能趕上在Method1這個例外是在Method2拋出?

回答

149

.NET 4及以上,您可以使用Task<T>類,而不是創建新的線程。然後,您可以在任務對象上使用.Exceptions屬性來獲取異常。 有2種方式來做到這一點:

  1. 在一個單獨的方法://你處理一些任務的線程

    class Program 
    { 
        static void Main(string[] args) 
        { 
         Task<int> task = new Task<int>(Test); 
         task.ContinueWith(ExceptionHandler, TaskContinuationOptions.OnlyOnFaulted); 
         task.Start(); 
         Console.ReadLine(); 
        } 
    
        static int Test() 
        { 
         throw new Exception(); 
        } 
    
        static void ExceptionHandler(Task<int> task) 
        { 
         var exception = task.Exception; 
         Console.WriteLine(exception); 
        } 
    } 
    
  2. 例外相同的方法://你處理例外在呼叫者的線程

    class Program 
    { 
        static void Main(string[] args) 
        { 
         Task<int> task = new Task<int>(Test); 
         task.Start(); 
    
         try 
         { 
          task.Wait(); 
         } 
         catch (AggregateException ex) 
         { 
          Console.WriteLine(ex);  
         } 
    
         Console.ReadLine(); 
        } 
    
        static int Test() 
        { 
         throw new Exception(); 
        } 
    } 
    

請注意,您得到的例外是AggregateException。所有真正的例外均可通過ex.InnerExceptions屬性獲得。

.NET 3.5您可以使用下面的代碼:

  1. 孩子的線程//你的過程異常

    class Program 
    { 
        static void Main(string[] args) 
        { 
         Exception exception = null; 
         Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), Handler)); 
         thread.Start();    
    
         Console.ReadLine(); 
        } 
    
        private static void Handler(Exception exception) 
        {   
         Console.WriteLine(exception); 
        } 
    
        private static void SafeExecute(Action test, Action<Exception> handler) 
        { 
         try 
         { 
          test.Invoke(); 
         } 
         catch (Exception ex) 
         { 
          Handler(ex); 
         } 
        } 
    
        static void Test(int a, int b) 
        { 
         throw new Exception(); 
        } 
    } 
    
  2. 或者//你處理例外來電者的線程

    class Program 
    { 
        static void Main(string[] args) 
        { 
         Exception exception = null; 
         Thread thread = new Thread(() => SafeExecute(() => Test(0, 0), out exception)); 
    
         thread.Start();    
    
         thread.Join(); 
    
         Console.WriteLine(exception);  
    
         Console.ReadLine(); 
        } 
    
        private static void SafeExecute(Action test, out Exception exception) 
        { 
         exception = null; 
    
         try 
         { 
          test.Invoke(); 
         } 
         catch (Exception ex) 
         { 
          exception = ex; 
         } 
        } 
    
        static void Test(int a, int b) 
        { 
         throw new Exception(); 
        } 
    } 
    
+0

對不起,但我忘了提及我正在使用.NET 3.5。根據我的理解任務是4.0的東西? – 2011-05-12 20:10:38

+2

@SilverlightStudent好吧,我剛更新了我的答案以滿足您的要求。 – oxilumin 2011-05-12 20:30:18

+0

@oxilumin:非常感謝,非常感謝。還有一個後續問題。如果你的Test()方法也有一些參數,那麼你將如何修改這些參數的SafeExecute方法? – 2011-05-13 14:34:50

6

您無法捕獲Method1中的異常。但是,您可以在Method2中捕獲異常並將其記錄到原始執行線程可以讀取和使用的變量中。

+0

感謝您的回覆。所以如果Method1是Class1的一部分,並且在該類中有一個類型爲Exception的變量。每當Method2引發異常時,它也會在Class1中設置該異常變量。這聽起來像一個公平的設計?有沒有處理這種情況的最佳實踐方法? – 2011-05-12 20:09:55

+0

正確,您只需存儲該異常並稍後訪問它。將來運行的方法(尤其是Method2完成時的回調函數)然後重新拋出異常,就好像它們自己造成了異常一樣,但這確實取決於您想要的結果。 – ermau 2011-05-12 20:14:12

1

到不同線程之間共享數據的最簡單的方法是shared data如下(一些是僞代碼):

class MyThread 
{ 
    public string SharedData; 

    public void Worker() 
    { 
     ...lengthy action, infinite loop, etc... 
     SharedData = "whatever"; 
     ...lengthy action... 
     return; 
    } 
} 

class Program 
{ 
    static void Main() 
    { 
     MyThread m = new MyThread(); 
     Thread WorkerThread = new Thread(m.Worker); 
     WorkerThread.Start(); 

     loop//or e.g. a Timer thread 
     { 
     f(m.SharedData); 
     } 
     return; 
    } 
} 

可以讀取關於在this nice introduction about multithreading該方法中,然而,我優選閱讀有關這個在O'Reilly book C# 3.0 in a nutshell中由Albahari(2007)兄弟提供,它也可以在Google Books上免費訪問,就像本書的較新版本一樣,因爲它還包括線程池,前景與後臺線程等等,示例代碼。 (免責聲明:我擁有本書的一個破舊的副本)

如果您正在製作WinForms應用程序,使用共享數據尤其方便,因爲WinForm控件不是線程安全的。使用回調將工作線程中的數據傳遞迴WinForm控件,主UI線程需要使用難以編碼的代碼Invoke()來使該控件成爲線程安全的。改爲使用共享數據,並使用單線程System.Windows.Forms.Timer和短時間Interval,例如0.2秒,您可以輕鬆地將信息從工作線程發送到控件,而無需使用Invoke