2010-10-20 32 views
8

Tại sao nó thích hợp hơn để ném ngoại lệ nàyMục đích của việc ném các lớp con ngoại lệ cụ thể là gì?

Throw New DivideByZeroException("You can't divide by zero") 

qua chung này:

Throw New Exception("You can't divide by zero") 

lợi thế là gì đạt được trong ví dụ cụ thể này? Tin nhắn đã nói lên tất cả. Các lớp con tiêu chuẩn kế thừa từ lớp Exception cơ sở có bao giờ có các phương thức khác nhau mà cơ sở đó không? Tôi đã không nhìn thấy một trường hợp, nhưng tôi phải thừa nhận rằng tôi có xu hướng ném ngoại lệ cơ bản.

+0

Vì bạn có thể bắt ngoại lệ cụ thể, bạn có thể có nhiều câu lệnh bắt trong khối try ... catch. – Nate

+0

"Các lớp con tiêu chuẩn kế thừa từ lớp Ngoại lệ cơ sở có bao giờ có các phương thức khác nhau mà cơ sở không?": Có, nhưng hầu hết các câu trả lời đều không tập trung vào điểm này. Kiểm tra 'WebException' cho một ví dụ đơn giản về điều này: http://msdn.microsoft.com/en-us/library/system.net.webexception.aspx. Cụ thể, lưu ý thuộc tính 'Response'. – Brian

Trả lời

20

Loại ngoại lệ cho phép trình xử lý ngoại lệ lọc bộ lọc. Nếu tất cả các bạn đã ném được ngoại lệ của loại Exception làm thế nào xử lý sẽ biết những gì ngoại lệ để bắt và cho phép để tuyên truyền lên ngăn xếp cuộc gọi?

Ví dụ, nếu bạn luôn ném Exception:

void Foo(string item) { 
    try { 
    if (Bar(item)) { 
     Console.WriteLine("BAR!"); 
    } 
    } catch (Exception e) { 
    Console.WriteLine("Something bad?"); 
    } 
} 

bool Bar(string item) { 
    if (item == null) { 
    throw new Exception("Argument is null!"); 
    } 

    return Int32.Parse(item) != 0; 
} 

Làm thế nào để người gọi Foo biết nếu một ngoại lệ vô xảy ra hoặc nếu Int32.Parse() thất bại? Nó phải kiểm tra loại của các ngoại lệ ném (hoặc làm một số so sánh chuỗi khó chịu).

Thậm chí còn đáng lo ngại hơn nếu bạn nhận được ThreadAbortException hoặc OutOfMemoryException có thể xảy ra ở những nơi bạn không mong đợi ngoại lệ. Trong những trường hợp này nếu mã bắt của bạn chỉ bắt được Exception, bạn có thể che giấu các ngoại lệ (quan trọng) này và gây thiệt hại cho trạng thái chương trình (hoặc hệ thống) của bạn.

Đoạn mã ví dụ nên đọc:

void Foo(string item) { 
    try { 
    if (Bar(item)) { 
     Console.WriteLine("BAR!"); 
    } 
    } catch (ArgumentNullException ae) { 
    Console.WriteLine("Null strings cannot be passed!"); 
    } catch (FormatException fe) { 
    Console.WriteLine("Please enter a valid integer!"); 
    } 
} 

bool Bar(string item) { 
    if (item == null) { 
    throw new ArgumentNullException("item"); 
    } 

    return Int32.Parse(item) != 0; 
} 
+0

+1, đẹp nhất ... –

+0

Để đi cùng với câu trả lời này: thông số Thư phải là chuỗi có thể đọc được. Chắc chắn bạn _could_ phân tích nó khi bạn bắt một ngoại lệ chung chung, nhưng đó là chi phí mà tôi không thích. Đặc biệt nếu tin nhắn có thể thay đổi. – Allan

7

Bởi vì bạn có thể có nhiều câu lệnh bắt và xử lý các lỗi khác nhau khác nhau.

Ví dụ, ngoại lệ DivideByZero có thể nhắc người dùng sửa mục nhập, trong khi ngoại lệ FileNotFound có thể cảnh báo người dùng rằng chương trình không thể tiếp tục và đóng chương trình.

Có một ngơi thoải mái tại bài viết chuyên sâu trả lời câu hỏi này ở đây: http://blogs.msdn.com/b/dotnet/archive/2009/02/19/why-catch-exception-empty-catch-is-bad.aspx

5

Thay vì lọc dựa trên văn bản gửi dọc theo suối lỗi, bạn có thể bắt nhiều loại ngoại lệ. Mỗi người có thể có một cách rất cụ thể để thực hiện phục hồi. Văn bản chỉ ở đó để cung cấp cho người dùng hoặc trình gỡ lỗi một số phản hồi, nhưng chương trình quan tâm đến loại ngoại lệ. Đối với cùng một lý do có tính đa hình cho các lớp do người dùng tạo ra, có các ngoại lệ. Nó dễ dàng hơn để bao gồm nhiều câu lệnh khai thác cho các loại ngoại lệ khác nhau hơn là phân tích cú pháp văn bản tin nhắn để hiểu những gì cần phải được thực hiện để xử lý chính xác vấn đề.

+0

cộng với phân tích cú pháp văn bản tin nhắn khi nội địa hóa của nó trở nên gần như không thể –

3

Các lớp con khác nhau của Ngoại lệ mang ý nghĩa ngữ nghĩa - một ArgumentNullException cho biết một vấn đề khác với một vấn đề tạo ra một DivideByZeroException và lập trình viên có thể xử lý các vấn đề này một cách khác nhau. Ngoài ra, các lớp con có thể xác định các thuộc tính hoặc phương thức bổ sung có thể hỗ trợ chẩn đoán hoặc xử lý sự cố, nếu lập trình viên chọn sử dụng chúng.

1
try { 
    Do(); 
} 
catch (MyException) 
{ 
    // reaction on MyException 
} 
catch (AnotherException) 
{ 
    // another reaction on AnotherException 
{ 
// SomeException will not be caught 


void Do() 
{ 
    if (...) 
     throw new MyException(); 
    else if (...) 
     throw new AnotherException(); 
    else 
     throw new SomeException(); 
} 
1

Trong một hệ thống phân cấp ngoại lệ được thiết kế tốt, có các loại ngoại lệ khác nhau, có thể có các phát biểu bắt giữ hành động khác nhau trong các trường hợp khác nhau. Lý tưởng nhất là, một nhóm ngoại lệ sẽ xuất hiện từ một hàm nếu hành động cụ thể không thể hoàn thành được, nhưng các biến thể lớp cần phải được áp dụng trước khi hành động được cố gắng vẫn giữ, ngoại trừ những hành động được ngụ ý bởi lỗi của hành động. Ví dụ, phương thức get-object của bộ sưu tập sẽ ném một ngoại lệ từ gia đình này nếu bộ sưu tập có vẻ hợp lệ nhưng đối tượng được yêu cầu không tồn tại.

Nếu hàm bị lỗi theo cách chỉ ra rằng các biến thể lớp không giữ khi nó được gọi, hoặc không còn giữ sau khi nó trả về, nó sẽ ném một ngoại lệ từ một gia đình khác. Lưu ý rằng nó có thể thích hợp cho một hàm để bắt một ngoại lệ từ gia đình đầu tiên và trở lại làm thứ hai, nếu cách duy nhất mà ngoại lệ xảy ra sẽ là nếu các bất biến bị vi phạm. Nó cũng có thể là thích hợp vào dịp để bắt một ngoại lệ của loại thứ hai và ném một trong những đầu tiên, nếu các trường hợp ngoại lệ đến từ một đối tượng mà không bao giờ sẽ được sử dụng sau khi chức năng trả về.

Nếu mọi thứ thực sự nghiêm trọng (ví dụ: Ngoại lệ OutOfMemoryException, CpuCatchingFireException, v.v.) phải là một phân cấp khác tách biệt với hai thứ nhất.

Các ngoại lệ hiện tại không tuân theo mẫu đó, nhưng người ta có thể sử dụng nó cho bất kỳ ngoại lệ mới nào tạo ra.

4

Trực tiếp từ MSDN - Exception Handling:

xem xét bắt ngoại lệ cụ thể khi bạn hiểu tại sao nó sẽ được ném vào một bối cảnh nhất định.

Bạn chỉ nên bắt những ngoại lệ mà bạn có thể khôi phục. Ví dụ: FileNotFoundException kết quả từ nỗ lực mở tệp không tồn tại có thể được ứng dụng xử lý vì ứng dụng có thể truyền đạt sự cố cho người dùng và cho phép người dùng chỉ định tên tệp khác hoặc tạo tệp. Yêu cầu mở tệp không tạo ra ExecutionEngineException không được xử lý vì nguyên nhân cơ bản của ngoại lệ không thể được biết với bất kỳ mức độ chắc chắn nào và ứng dụng không thể đảm bảo rằng việc tiếp tục thực hiện là an toàn.

Đừng lạm dụng catch, như ném một ngoại lệ từ bên trong một khối catch sẽ thiết lập lại stack trace và gây ra mất thông tin gỡ lỗi quan trọng, vì một lần nữa MSDN gợi ý:

Đừng lạm dụng bắt lấy. Các ngoại lệ nên thường được phép phổ biến ngăn xếp cuộc gọi.

Ghi lại các ngoại lệ mà bạn không thể xử lý hợp pháp thông tin gỡ lỗi quan trọng.

Cuối cùng, bắt một ngoại lệ nên để xử lý ngoại lệ cụ thể mà bạn mong đợi xảy ra dưới kịch bản phổ biến nhất định mà bạn muốn đăng nhập hoặc có một số hành vi cụ thể khi ngoại lệ bắt, nếu không chỉ đơn giản là throw nó đi, như số Eric Lippert tự giới thiệu trên blog của mình (xem Too much reuse bài viết).

try { 
    ... 
} catch (Exception ex) { 
    throw; // This does not reset the stack trace. 
} 

Thay vì:

try { 
    ... 
} catch (Exception ex) { 
    throw ex; // This does reset the stack trace. 
} 

Cuối cùng, một Exception không cần không bắt buộc để cung cấp một số đặc trưng như tính chất bổ sung hoặc các phương pháp hoặc bất cứ điều gì, nó là tên của nó mà nói ra cho bản thân, cho phép bạn để lọc bắt của bạn khi một loại ngoại lệ cụ thể.

EDIT # 1

Một liên kết thú vị về xử lý trên Eric Lippert blog lỗi: Vexing exceptions.

3

Trường hợp ngoại lệ thường là (1) bị bắt, đăng nhập và bị ném lại, (2) bị bắt và xử lý hoặc (3) không bị bắt.

Nếu nó bị bắt, ghi lại và được ném lại thì có thể có thêm thông tin quan trọng được lưu trữ trong một loại ngoại lệ cụ thể cho phép mã đăng nhập kết xuất thông tin phong phú hơn để nhà phân tích đang cố gỡ lỗi gây ra ngoại lệ có thể làm như vậy hiệu quả hơn.

Nếu bị bắt và xử lý thì bạn cần biết cách xử lý sự cố. Nếu một ngoại lệ là một loại cụ thể thì đó là một đầu mối lớn cho nhà phát triển, người đang viết trình xử lý về việc liệu họ có thể xử lý ngoại lệ hay không. Bạn chỉ nên xử lý các ngoại lệ mà bạn mong đợi và biết cách phục hồi.

Nếu nó không bị bắt thì quá trình sẽ chuyển xuống và có thể một bãi chứa sự cố sẽ được gửi đi đâu đó. Bây giờ chúng tôi trở lại trong trường hợp (1).

Trong cả ba trường hợp, có nhiều thông tin loại hơn thích hợp hơn để có ít hơn.

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