2011年7月27日 星期三

發生例外時該用Throw ex or Throw?

當我們在try block發生例外時,如果需要在catch block處理完例外後,要將原來的例外抛回呼叫端,大家是會用throw或是throw ex呢?雖然這2種語法皆可以把例外再抛回呼叫端,如果你在呼叫端攔到Exception時show ex.Message則都可以看到同樣的例外訊息,不過這2個語法還是有一點不一樣,以下列程式片段為例:
   1: using System;
   2:  
   3: namespace ConsoleApplication1
   4: {
   5:     class Program
   6:     {
   7:         static void Main()
   8:         {
   9:             try
  10:             {
  11:                 TestEx1();
  12:             }
  13:             catch (Exception ex)
  14:             {
  15:                 Console.WriteLine("TestEx1:" + ex.ToString());
  16:             }
  17:  
  18:             Console.Read();
  19:         }
  20:  
  21:         static void TestEx1()
  22:         {
  23:  
  24:             try
  25:             {
  26:                 int a = int.Parse("");
  27:             }
  28:             catch (Exception ex)
  29:             {
  30:  
  31:                 throw ;
  32:             }
  33:         }
  34:  
  35:     }
  36: }
如果你用throw ex,則在Main的ex.ToString中,所得到的內容如下:
TestEx1:System.FormatException: 輸入字串格式不正確。
於 ConsoleApplication1.Program.TestEx1() 於 C:\Users\Administrator\Desktop\ConsoleApplication3\ConsoleApplication3\Program.cs: 行 31
於 ConsoleApplication1.Program.Main(String[] args) 於 C:\Users\Administrator\Desktop\ConsoleApplication3\ConsoleApplication3\Program.cs: 行 11
堆疊最上層的行31是指throw ex那一行,而不是真正發生例外的int.Parse那一行;如果將程式的第31行throw ex改為throw,則ex.ToString則得到的例外內容如下:
TestEx1:System.FormatException: 輸入字串格式不正確。
於 System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
於 System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
於 System.Int32.Parse(String s)   於 ConsoleApplication1.Program.TestEx1() 
於 C:\Users\Administrator\Desktop\ConsoleApplication3\ConsoleApplication3\Program.cs: 行 31
於 ConsoleApplication1.Program.Main(String[] args) 於 C:\Users\Administrator\Desktop\ConsoleApplication3\ConsoleApplication3\Program.cs: 行 11
有沒有發現例外發生的真正原因是從Int32.Parse一直到最底層StringToNumber(難怪int.Parse參數一定要傳string,原來是底層會先做字串轉數字動作),都有show出來.也就是當你用throw ex抛出例外時,.Net會清除原始的Stack再抛出例外,所以呼叫端看到的Stack是從throw ex那一行開始算,使用throw才能保留原始Stack的內容.
所以囉,最好還是使用throw而不要使用throw ex來抛出原例外,以免看不到真正發生的原因. 
 

沒有留言:

張貼留言