2013-05-14 77 views
7

我試圖運行下面的代碼:爲什麼這個異常沒有被捕獲?

class Program 
{ 
    static void Main(string[] args) 
    { 
     var task = Task.Factory.StartNew(() => 
      { 
       throw new ApplicationException("message"); 
      }); 
     try 
     { 
      task.ContinueWith(t => Console.WriteLine("End")); 
     } 
     catch (AggregateException aex) 
     { 
      Console.Write(aex.InnerException.Message); 
     } 
    } 
} 

我預計Exception將在以下位置被抓:

 catch (AggregateException aex) 
     { 
      Console.Write(aex.InnerException.Message); 
     } 

但這沒有發生。這是爲什麼?

+0

回答涉及什麼以及如何做,但不是「爲什麼」(異常未捕獲)。我相信這個基本原理非常重要,在Stephen Toub的文章[.NET 4.5中的任務異常處理](http://blogs.msdn.com/b/pfxteam/archive/2011/09/28/10217876)中有解釋。 aspx)這是一個必讀] – 2013-05-17 03:23:27

回答

9

你只是打印出task - 這不會甚至還沒有完成。

打印該任務不會等待它完成,或嘗試獲取該值。

如果你改變你的代碼:

try 
{ 
    task.Wait(); 
} 

... 然後我希望它捕獲異常。

(我以前使用Task<T>.Result,但我發現這是一個沒有返回值的任務,所以它也只是非通用Task

+0

@NominSim號。當'StartNew'返回時,委託本身還沒有運行。當甚至還沒有到達異常時,它不能在該行上拋出異常。 – Servy 2013-05-14 17:11:36

+1

@NominSim:它被攔截的'Result'屬性獲取。 – 2013-05-14 17:11:56

+1

@NominSim ApplicationException是從另一個線程拋出的。在那個線程中,這就是調用提供的匿名委託,它最終會被捕獲(在'Task'代碼的內部某個catch塊中)。創建任務時不會從主線程重新拋出。當主線程等待任務時,一旦任務完成,它會注意到任務以頂級異常結束;那麼這個異常在主線程中被重新拋出(在一個封裝的'AggregateException'中),因爲這就是'Wait'方法的實現明確做到的。 – Servy 2013-05-14 17:22:07

-4

因爲你的說法是不是在嘗試,但前... CATCH將抓住每一個例外,從內儘量大括號...

+3

我認爲你誤解了任務的本質。 – 2013-05-14 17:12:14

+0

這根本不是真的。一個簡單的反例:將'try'塊的主體設置爲'task.Result',它最終將重新拋出在定義任務的委託中生成的異常。 – Servy 2013-05-14 17:12:31

+0

@Jon Skeet>我認爲我已經誤解了整個問題的真相:-) – 2013-05-14 17:13:24

1

的方式Task的行爲,最終調用的代碼您傳遞給StartNew的代表最終將被捕獲,並且Exception將被存儲在任務的實例字段中。通過查看task.Exception屬性,可以檢查該例外情況。行Console.WriteLine(task)只是在內部調用task.ToString。該方法不會導致異常被拋出或重新拋出。

但是,在某些情況下,被捕獲的異常將被重新拋出。兩個示例是在訪問Result時調用Wait以及在await中執行C#5.0中的任務。

以下代碼:

try 
{ 
    task.Wait(); 
} 
catch (AggregateException aex) 
{ 
    Console.Write(aex.InnerException.Message); 
} 

將導致存儲異常被重新拋出,將被打印的異常消息。

+0

除了即使使用分號,也不能使用屬性訪問作爲自己的語句。 – 2013-05-14 17:12:37

+0

@LuisFilipe我已經編輯了他所指的錯誤。只需查看修訂歷史即可。 – Servy 2013-05-14 17:25:47

+0

@LuisFilipe其實,我在5分鐘的時間內修正了它,所以它甚至不會在修訂歷史中;但自從我修好之後,我犯了一個錯誤。 – Servy 2013-05-14 17:26:21

-2

AggregateException和ApplicationException都是同一個類System.Exception的子類。 AggregateException is-not a ApplicationException

+1

這是無關緊要的。 OP的'try'塊沒有任何異常。 – Servy 2013-05-14 17:15:56

+0

是的,我打算冒險,說'拋出新的ApplicationException(「message」);'不是這個任務的真正實現。這可能是創造榜樣的錯誤,與真實問題無關。 – 2013-05-14 17:18:19

+0

@NickFreeman沒有。這根本不是真的。 'Task'類將在'AggregateException'中包裝從其正文中拋出的任何異常,因此使用該異常是適當的。正如我在我的回答中所描述的,問題是OP需要使用'task.Wait()'。這一小小的變化導致程序完全按照預期工作。 – Servy 2013-05-14 17:23:58