2010-06-08 49 views
116

sự khác biệt giữachênh lệch giữa ném và ném ngoại lệ mới()

try { ... } 
catch{ throw } 

try{ ... } 
catch(Exception e) {throw new Exception(e.message) } 

là gì Dù rằng thứ hai cho thấy một tin nhắn?

+38

Đoạn mã thứ hai là một trong những dòng mã độc nhất (nhưng vô hại) mà tôi từng thấy. – SLaks

+0

http://stackoverflow.com/questions/22623/net-throwing-exceptions-best-practices – dotjoe

Trả lời

188

throw; trả về ngoại lệ ban đầu và duy trì theo dõi ngăn xếp ban đầu.

throw ex; ném ngoại lệ ban đầu nhưng đặt lại theo dõi ngăn xếp, hủy tất cả thông tin theo dõi ngăn xếp cho đến khối catch của bạn.


KHÔNG BAO GIỜ ghi throw ex;


throw new Exception(ex.Message); thậm chí còn tồi tệ hơn. Nó tạo ra một phiên bản Exception hoàn toàn mới, mất dấu vết ngăn xếp ban đầu của ngoại lệ, cũng như loại của nó. (ví dụ: IOException).
Ngoài ra, một số ngoại lệ giữ thông tin bổ sung (ví dụ: ArgumentException.ParamName).
throw new Exception(ex.Message); cũng sẽ hủy thông tin này.

Trong một số trường hợp, bạn có thể muốn bao bọc tất cả ngoại lệ trong đối tượng ngoại lệ tùy chỉnh, để bạn có thể cung cấp thêm thông tin về mã đang làm khi ngoại lệ được ném.

Để làm điều này, định nghĩa một lớp mới kế thừa Exception, add all four exception constructors, và tùy chọn một nhà xây dựng bổ sung mà phải mất một InnerException cũng như biết thêm chi tiết, và vứt lớp ngoại lệ mới của bạn, qua ex như InnerException tham số . Bằng cách chuyển số InnerException gốc, bạn bảo toàn tất cả các thuộc tính của ngoại lệ ban đầu, bao gồm cả dấu vết ngăn xếp.

+13

"ném ngoại lệ mới (cũ); thậm chí tệ hơn.": Tôi không đồng ý về điều này. Đôi khi bạn muốn thay đổi loại của một ngoại lệ, và sau đó giữ ngoại lệ ban đầu là ngoại lệ bên trong là tốt nhất bạn có thể làm. Mặc dù nó nên là 'ném mới MyCustomException (myMessage, cũ); 'tất nhiên. –

+8

@ 0xA3: Tôi có nghĩa là 'ex.Message', _is_ tồi tệ hơn. – SLaks

+6

Ngoài việc triển khai các hàm tạo tiêu chuẩn, bạn cũng nên tạo các ngoại lệ tùy chỉnh '[Serializable()]'. –

4

throw tái ném ngoại lệ đã bắt, giữ lại dấu vết ngăn xếp, trong khi throw new Exception mất một số chi tiết về ngoại lệ bị bắt.

Thông thường, bạn sẽ tự sử dụng throw để đăng nhập ngoại lệ mà không xử lý hoàn toàn tại thời điểm đó.

BlackWasp có một bài viết hay có tiêu đề đầy đủ là Throwing Exceptions in C#.

3

throw là để thực hiện lại ngoại lệ bị bắt. Điều này có thể hữu ích nếu bạn muốn làm điều gì đó với ngoại lệ trước khi chuyển nó lên chuỗi cuộc gọi.

Sử dụng throw mà không có bất kỳ đối số nào giữ nguyên ngăn xếp cuộc gọi cho mục đích gỡ lỗi.

3

Ném ngoại lệ mới sẽ thổi đi dấu vết ngăn xếp hiện tại.

throw; sẽ giữ lại dấu vết ngăn xếp ban đầu và hầu như luôn hữu ích hơn. Ngoại lệ cho quy tắc đó là khi bạn muốn bao gồm Ngoại lệ trong Ngoại lệ tùy chỉnh của riêng bạn. Sau đó bạn nên làm:

catch(Exception e) 
{ 
    throw new CustomException(customMessage, e); 
} 
0

Nếu bạn muốn bạn có thể ném Ngoại lệ mới, với trường hợp ban đầu được đặt làm ngoại lệ bên trong.

19

Đầu tiên giữ gìn stacktrace gốc:

try { ... } 
catch 
{ 
    // Do something. 
    throw; 
} 

Thứ hai cho phép bạn thay đổi kiểu của ngoại lệ và/hoặc tin nhắn và dữ liệu khác:

try { ... } catch (Exception e) 
{ 
    throw new BarException("Something broke!"); 
} 

Ngoài ra còn có một cách thứ ba nơi bạn vượt qua ngoại lệ bên trong:

try { ... } 
catch (FooException e) { 
    throw new BarException("foo", e); 
} 

Tôi khuyên bạn nên sử dụng:

  • là người đầu tiên nếu bạn muốn làm một số ngẫu nhiên trong tình huống lỗi mà không phá hủy thông tin hoặc thêm thông tin về lỗi.
  • thứ ba nếu bạn muốn thêm thông tin khác về lỗi.
  • giây nếu bạn muốn ẩn thông tin (từ người dùng không đáng tin cậy).
0

Ví dụ thứ hai của bạn sẽ đặt lại dấu vết ngăn xếp của ngoại lệ. Việc đầu tiên chính xác nhất bảo tồn nguồn gốc của ngoại lệ. Ngoài ra, bạn đã mở khóa loại ban đầu là yếu tố quan trọng trong việc biết điều gì thực sự đã xảy ra ... Nếu thứ hai là bắt buộc đối với chức năng - ví dụ: Để thêm thông tin mở rộng hoặc tái bọc với loại đặc biệt, chẳng hạn như tùy chỉnh 'HandleableException', hãy đảm bảo rằng thuộc tính InnerException cũng được đặt!

+0

Ồ, khi tôi bắt đầu viết, chưa có câu trả lời nào và bây giờ tôi ' số 6 ... – Reddog

+0

Vâng, đây là một trong những câu hỏi mà bạn phải viết nhanh.;) –

0

Sự khác biệt quan trọng nhất là biểu thức thứ hai sẽ xóa loại ngoại lệ. Và loại trừ đóng vai trò quan trọng trong trường hợp ngoại lệ bắt:

public void MyMethod() 
{ 
    // both can throw IOException 
    try { foo(); } catch { throw; } 
    try { bar(); } catch(E) {throw new Exception(E.message); } 
} 

(...) 

try { 
    MyMethod(); 
} catch (IOException ex) { 
    Console.WriteLine ("Error with I/O"); // [1] 
} catch (Exception ex) { 
    Console.WriteLine ("Other error"); // [2] 
} 

Nếu foo() ném IOException, [1] khối catch sẽ bắt ngoại lệ. Nhưng khi bar() ném IOException, nó sẽ được chuyển thành đồng bằng Exception kiến ​​sẽ không bị phát hiện bởi [1] khối catch.

3

Một điểm khác mà tôi không thấy bất cứ ai thực hiện:

Nếu bạn không làm bất cứ điều gì trong nắm bắt của bạn {} khối, có một try ... catch là vô nghĩa. Tôi thấy điều này tất cả các thời gian:

try 
{ 
    //Code here 
} 
catch 
{ 
    throw; 
} 

Hoặc tệ hơn:

try 
{ 
    //Code here 
} 
catch(Exception ex) 
{ 
    throw ex; 
} 

tệ nhất được nêu ra:

try 
{ 
    //Code here 
} 
catch(Exception ex) 
{ 
    throw new System.Exception(ex.Message); 
} 
+0

Tôi đồng ý, trừ khi bạn có điều khoản cuối cùng. –

0

ném hoặc ném ex, cả hai đều được sử dụng để ném hoặc rethrow ngoại lệ, khi bạn chỉ cần đăng nhập thông tin lỗi và không muốn gửi bất kỳ thông tin nào trở lại cho người gọi, bạn chỉ cần đăng nhập lỗi khi bắt và thoát.Nhưng trong trường hợp bạn muốn gửi một số thông tin có ý nghĩa về ngoại lệ cho người gọi bạn sử dụng ném hoặc ném ex. Bây giờ sự khác biệt giữa throw và throw ex là throw bảo tồn stack trace và các thông tin khác nhưng throw ex tạo một đối tượng ngoại lệ mới và do đó stack stack gốc bị mất. Vì vậy, khi chúng ta nên sử dụng ném và ném e, Vẫn còn một vài tình huống mà trong đó bạn có thể muốn xem xét lại một ngoại lệ như để đặt lại thông tin ngăn xếp cuộc gọi. Ví dụ: nếu phương thức nằm trong thư viện và bạn muốn ẩn chi tiết của thư viện khỏi mã gọi, bạn không nhất thiết muốn ngăn xếp cuộc gọi bao gồm thông tin về các phương thức riêng tư trong thư viện. Trong trường hợp đó, bạn có thể bắt ngoại lệ trong các phương thức công khai của thư viện và sau đó thử lại chúng để ngăn xếp cuộc gọi bắt đầu tại các phương thức công khai đó.

0

Ném; Rethrow ngoại lệ ban đầu và giữ kiểu ngoại lệ.

Ném ngoại lệ mới(); Quay lại loại ngoại lệ ban đầu và đặt lại dấu vết ngăn xếp ngoại lệ

Ném ví dụ; Đặt lại dấu vết ngăn xếp ngoại lệ và đặt lại loại ngoại lệ

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