2017-05-05 137 views
4

我寫了簡單的C#控制檯應用程序:異常拋出catch和最後。 CLR行爲與try-catch塊

class Mystery 
{ 
    static void Main(string[] args) 
    { 
     MakeMess(); 
    } 

    private static void MakeMess() 
    { 
     try 
     { 
      System.Console.WriteLine("try"); 
      throw new Exception(); // let's invoke catch 
     } 
     catch(Exception) 
     { 
      System.Console.WriteLine("catch"); 
      throw new Exception("A"); 
     } 
     finally 
     { 
      System.Console.WriteLine("finally"); 
      throw new Exception("B"); 
     } 
    } 
} 

控制檯給出的輸出是:

嘗試

未處理的異常: System.Exception:A在Mystery.Program.MakeMess()in ...

看來,CLR抓到了A並且finally塊沒有被調用。

但是,當我周圍調用MakeMess()的try-catch塊:

static void Main(string[] args) 
{ 
    try 
    { 
     MakeMess(); 
    } 
    catch(Exception ex) 
    { 
     System.Console.WriteLine("Main caught " + ex.Message); 
    } 
} 

輸出看起來完全不同:

嘗試

終於

Main被捕獲B

當Exception嚴格在方法外部處理時,從MakeMess()傳播的異常看起來不同。

這種行爲的解釋是什麼?

+0

如果你在編譯器之外運行,會發生什麼?我認爲最後會寫成 – TheLethalCoder

+2

請參閱http://stackoverflow.com/a/1555578/613130 *一個重要的注意事項是,如果e未被try/catch塊捕獲到進一步向上調用堆棧或由全局處理異常處理程序,那麼finally塊可能永遠不會執行。* – xanatos

+0

你沒有捕獲異常。程序停止。當某些事情完全失敗時沒有理由繼續。在你的秒示例中,它與嵌套try catch相同。外部嘗試將捕獲內部捕獲的異常。但在此之前最終會被調用。 –

回答

2

您看到的行爲與finally塊投擲與否無關。您只需在應用程序中未處理的異常,這種情況發生的時候,所有的賭注都關閉,其中包括如果finally塊運行或不:

MSDN文件:

在一個處理的異常,與之關聯的finally塊保證運行。但是,如果異常未處理,finally塊的執行取決於如何觸發異常展開操作。這反過來又取決於你的電腦設置方式。有關更多信息,請參閱CLR中的未處理的異常處理。

通常,當未處理的異常結束應用程序時,是否運行finally塊並不重要。但是,如果在finally塊中有語句,即使在這種情況下也必須運行,一種解決方案是將catch塊添加到try-finally語句中。或者,您可以捕獲可能在調用堆棧上方try-finally語句的try塊中拋出的異常。也就是說,您可以在調用包含try-finally語句的方法或調用該方法的方法或調用堆棧中的任何方法中捕獲異常。如果未捕獲異常,則執行finally塊取決於操作系統是否選擇觸發異常展開操作。

如果finally塊必須運行,那麼解決方案恰恰是你在第二個片段做了什麼事:處理未處理的異常。

-1

What happens if a finally block throws an exception?

C#4語言規範§8.9.5:如果最後塊拋出另一個異常,則當前異常的處理被終止。

我認爲finally塊最終只適用於cleanig資源,不應該拋出任何異常。

+0

這是如何以任何方式回答問題的? – InBetween