2013-02-04 30 views
13

Tôi đọc rằng khi ở trong khối catch, tôi có thể rút lại ngoại lệ hiện tại bằng cách sử dụng "throw;" hoặc "ném cũ;"Tại sao "ném" và "ném cũ" trong một khối catch hoạt động theo cùng một cách?

Từ: http://msdn.microsoft.com/en-us/library/ms182363%28VS.80%29.aspx

"Để giữ cho thông tin stack trace ban đầu với các ngoại lệ, sử dụng câu lệnh ném mà không chỉ định các ngoại lệ."

Nhưng khi tôi thử điều này với

 try{ 
      try{ 
       try{ 
        throw new Exception("test"); // 13 
       }catch (Exception ex1){ 
        Console.WriteLine(ex1.ToString()); 
        throw; // 16 
       } 
      }catch (Exception ex2){ 
       Console.WriteLine(ex2.ToString()); // expected same stack trace 
       throw ex2; // 20 
      } 
     }catch (Exception ex3){ 
      Console.WriteLine(ex3.ToString()); 
     } 

tôi nhận được ba ngăn xếp khác nhau. Tôi đã mong đợi dấu vết đầu tiên và thứ hai giống nhau. Tôi đang làm gì sai? (Hoặc hiểu sai?)

System.Exception: test tại ConsoleApplication1.Program.Main (String [] args) trong c: \ Program.cs: dòng 13 System.Exception: test tại ConsoleApplication1.Program. Main (String [] args) trong c: \ Program.cs: line 16 System.Exception: test tại ConsoleApplication1.Program.Main (String [] args) trong c: \ Program.cs: dòng 20

+0

yep, đọc lại tuyên bố.để giữ cho dấu vết ngăn xếp làm 'ném' không phải' ném ex2' –

+0

Những người, hãy đọc mã thực tế. Trong một trường hợp, OP chỉ sử dụng 'throw' và trong trường hợp khác, chúng sử dụng' throw ex'. Tuy nhiên, trong tất cả * ba * trường hợp (nghĩa là, không chỉ trường hợp với 'ném ex'), có ba ngăn xếp khác nhau (được cho là). Nếu các dấu vết ngăn xếp thực sự khác nhau, thì đây thực sự là một câu hỏi thú vị. – siride

+1

@mitch nếu bạn đọc câu hỏi, những gì tài liệu nói và những gì tôi quan sát là khác nhau! Đây là những gì tôi muốn làm rõ. Tại sao ex1 và ex2 ngăn xếp khác nhau nếu tôi nghĩ lại với "ném"? – cquezel

Trả lời

7

throw sẽ chỉ giữ nguyên khung ngăn xếp nếu bạn không ném nó từ bên trong khung hiện tại. Bạn đang làm điều đó bằng cách thực hiện tất cả điều này trong một phương pháp.

Xem câu trả lời này: https://stackoverflow.com/a/5154318/1517578

PS: +1 cho hỏi một câu hỏi mà thực sự là một câu hỏi hợp lệ.

2

Simon đánh bại tôi để trả lời, nhưng bạn có thể thấy hành vi dự kiến ​​chỉ đơn giản bằng cách ném ngoại lệ ban đầu từ bên trong chức năng khác:

static void Main(string[] args) 
{ 
    try 
    { 
     try 
     { 
      try 
      { 
       Foo(); 
      } 
      catch (Exception ex1) 
      { 
       Console.WriteLine(ex1.ToString()); 
       throw; 
      } 
     } 
     catch (Exception ex2) 
     { 
      Console.WriteLine(ex2.ToString()); // expected same stack trace 
      throw ex2; 
     } 
    } 
    catch (Exception ex3) 
    { 
     Console.WriteLine(ex3.ToString()); 
    } 
} 

static void Foo() 
{ 
    throw new Exception("Test2"); 
} 
+0

cảm ơn! Nhưng bạn có nhận thấy nội dung ngăn xếp của mình không? Dòng 1 được bảo quản nhưng dòng 2 khác nhau (theo dấu vết thứ nhất và thứ hai). Tôi cũng không mong đợi điều này. – cquezel

+0

Và tôi đoán điều này sẽ trở lại câu trả lời của Simon. Nhưng tôi nghĩ rằng điều này là tốt hơn để gỡ lỗi, bởi vì bạn biết vị trí cuối cùng trong mã của bạn đã được thực hiện trước khi ngoại lệ thực sự trở thành một vấn đề. –

2

Vâng, tôi đào một chút về vấn đề này và đây là của tôi rất cá nhân kết luận:

Không bao giờ sử dụng “ném” ”nhưng luôn luôn thay đổi một ngoại lệ mới với nguyên nhân được chỉ định.

Đây là lập luận của tôi:

tôi bị ảnh hưởng bởi kinh nghiệm trước đây của tôi với Java và dự kiến ​​C# ném là rất tương tự như của Java. Vâng, tôi đào thêm một chút về vấn đề này và đây là những quan sát của tôi:

static void Main(string[] args){ 
     try { 
      try { 
       throw new Exception("test"); // 13 
      } 
      catch (Exception ex) { 
       Console.WriteLine(ex.ToString()); 
       throw ex;// 17 
      } 
     } catch (Exception ex) { 
      Console.WriteLine(ex.ToString()); 
     } 
    } 

Sản lượng:

System.Exception: test 
    at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13 
System.Exception: test 
    at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 17 

trực giác, một lập trình viên Java lại có thể ngờ cả hai trường hợp ngoại lệ là như nhau:

System.Exception: test 
    at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13 

Nhưng tài liệu C# rõ ràng nói rằng đây là những gì được mong đợi:

Nếu một ngoại lệ được tái ném bằng cách xác định ngoại trừ trong báo cáo ném, stack trace được khởi động lại vào phương pháp hiện tại và danh sách các phương pháp gọi giữa các phương pháp ban đầu mà ném ngoại lệ và các phương pháp hiện hành sẽ bị mất.Để giữ thông tin theo dõi ngăn xếp ban đầu với ngoại lệ, hãy sử dụng câu lệnh ném mà không chỉ định ngoại lệ. ”

Bây giờ nếu tôi thay đổi một chút thử nghiệm (thay thế ném cũ; bằng cách ném; trên dòng 17).

 try { 
      try { 
       throw new Exception("test"); // 13 
      } 
      catch (Exception ex) { 
       Console.WriteLine(ex.ToString()); 
       throw;// 17 
      } 
     } catch (Exception ex) { 
      Console.WriteLine(ex.ToString()); 
     } 

Sản lượng:

System.Exception: test 
    at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13 
System.Exception: test 
    at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 17 

Rõ ràng đây không phải là những gì tôi mong đợi (vì đây là câu hỏi ban đầu). Tôi bị mất điểm ném ban đầu trong dấu vết ngăn xếp thứ hai. Simon Whitehead liên kết lời giải thích, đó là việc ném; duy trì dấu vết ngăn xếp chỉ khi ngoại lệ không xảy ra trong phương pháp hiện tại. Vì vậy, "ném" mà không có tham số trong cùng một phương pháp là khá vô ích như, nói chung, nó sẽ không giúp bạn tìm ra nguyên nhân của ngoại lệ.

Làm những gì bất kỳ lập trình viên Java sẽ làm gì, tôi đã thay thế báo cáo kết quả trên dòng 17 theo:

throw new Exception("rethrow", ex);// 17 

Sản lượng:

System.Exception: test 
    at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13 

System.Exception: rethrow ---> System.Exception: test 
    at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 13 
    --- End of inner exception stack trace --- 
    at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 17 

mà là một kết quả tốt hơn nhiều.

Sau đó, tôi bắt đầu thử nghiệm với các cuộc gọi phương thức.

private static void throwIt() { 
     throw new Exception("Test"); // 10 
    } 

    private static void rethrow(){ 
     try{ 
      throwIt(); // 15 
     } catch (Exception ex) { 
      Console.WriteLine(ex.ToString()); 
      throw; // 18 
     } 
    } 

    static void Main(string[] args){ 
     try{ 
      rethrow(); // 24 
     } catch (Exception ex) { 
      Console.WriteLine(ex.ToString()); 
     } 
    } 

Một lần nữa, dấu vết ngăn xếp không phải là những gì tôi (một lập trình Java) mong đợi. Trong Java, cả hai ngăn xếp sẽ giống nhau và có ba phương thức sâu dưới dạng:

java.lang.Exception: Test 
    at com.example.Test.throwIt(Test.java:10) 
    at com.example.Test.rethrow(Test.java:15) 
    at com.example.Test.main(Test.java:24) 

Dấu vết ngăn xếp đầu tiên chỉ có hai phương thức sâu.

System.Exception: Test 
    at ConsoleApplication1.Program.throwIt() in Program.cs:line 10 
    at ConsoleApplication1.Program.rethrow() in Program.cs:line 15 

Nó giống như là dấu vết ngăn xếp đã được phổ biến như một phần của quá trình giải phóng ngăn xếp. Nếu tôi đăng nhập theo dõi ngăn xếp để điều tra ngoại lệ tại thời điểm đó, có thể tôi đang thiếu thông tin quan trọng.

Dấu vết ngăn xếp thứ hai là ba phương pháp sâu nhưng dòng 18 (ném;) xuất hiện trong đó.

System.Exception: Test 
    at ConsoleApplication1.Program.throwIt() in Program.cs:line 10 
    at ConsoleApplication1.Program.rethrow() in Program.cs:line 18 
    at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 24 

Quan sát này tương tự như quan sát được thực hiện trước đó: dấu vết ngăn xếp không được giữ nguyên cho phạm vi phương pháp hiện tại và lần nữa tôi loại bỏ phương thức được gọi là ngoại lệ. Ví dụ, nếu rethow được viết như sau:

private static void rethrow(){ 
    try{ 
     if (test) 
      throwIt(); // 15 
     else 
      throwIt(); // 17 
    } catch (Exception ex) { 
     Console.WriteLine(ex.ToString()); 
     throw; // 20 
    } 
} 

sản lượng

System.Exception: Test 
    at ConsoleApplication1.Program.throwIt() in Program.cs:line 10 
    at ConsoleApplication1.Program.rethrow() in Program.cs:line 20 
    at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 26 

nào gọi đến throwIt() ném ngoại lệ? Stack nói dòng 20 là dòng 15 hay 17?

Giải pháp là giống như trước: quấn nguyên nhân trong một ngoại lệ mới trong đó sản lượng:

System.Exception: rethrow ---> System.Exception: Test 
    at ConsoleApplication1.Program.throwIt() in Program.cs:line 10 
    at ConsoleApplication1.Program.rethrow(Boolean test) in Program.cs:line 17 
    --- End of inner exception stack trace --- 
    at ConsoleApplication1.Program.rethrow(Boolean test) in Program.cs:line 20 
    at ConsoleApplication1.Program.Main(String[] args) in Program.cs:line 26 

kết luận đơn giản của tôi để tất cả điều này là không bao giờ sử dụng “ném;” nhưng luôn rethrow mới ngoại lệ với nguyên nhân được chỉ định.

Các vấn đề liên quan