Chương 7 Quản lý lỗ
7.4. Ném biệt lệ lần nữa.
Sẽ có trường hợp ta muốn rằng trong khối lệnh catch ta sẽ khởi động một hành
động sửa lỗi, và sau đó ném biệt lệ cho khối try khác (khối try của hàm gọi). Biệt lệ
này có thể cùng loại hay khác loại với biệt lệ khối catch bắt được. Nếu là cùng loại, khối catch sẽ ném biệt lệ này một lần nữa; còn nếu khác loại, ta sẽ nhúng biệt lệ cũ
vào biệt lệ mới để khối try hàm gọi biết được lịch sử của biệt lệ. Property InnerException được dủng để thực hiện việc này. Biệt lệ đem nhúng gọi là biệt lệ
nội.Bởi vì InnerException cũng chính là một biệt lệ nên nó cũng có InnerException của nó. Cứ như vậy tạo nên một loạt các biệt lệ. Ví dụ 7-8. Ném biệt lệ lần nữa và biệt lệ nội (inner exception) using System; namespace Programming_CSharp {
public class MyCustomException: System.Exception {
public MyCustomException(string message,Exception inner): base(message,inner)
{ } }
public class Test {
public static void Main() {
Test t = new Test(); t.TestFunc();
}
public void TestFunc() {
try {
DangerousFunc1(); }
// khi bắt được biệt lệ tự tạo // in lịch sử các biệt lệ
catch (MyCustomException e) {
Console.WriteLine("\n{0}", e.Message);
Console.WriteLine("Retrieving exception history..."); Exception inner = e.InnerException;
while (inner != null) { Console.WriteLine("{0}",inner.Message); inner = inner.InnerException; } } }
public void DangerousFunc1( ) {
try {
DangerousFunc2( ); }
// nếu bắt được một biệt lệ // ném một biệt lệ tự tạo catch(System.Exception e) {
MyCustomException ex = new MyCustomException("E3 - Custom Exception Situation!",e);
throw ex; } }
public void DangerousFunc2( ) {
try {
DangerousFunc3( ); }
// nếu bắt được biệt lệ DivideByZeroException thực hiện // vài công việc sữa lỗi và ném ra biệt lệ tổng quát
catch (System.DivideByZeroException e) {
Exception ex = new Exception("E2 - Func2 caught divide by zero",e); throw ex;
} }
public void DangerousFunc3( ) { try { DangerousFunc4( ); } catch (System.ArithmeticException) { throw; } catch (System.Exception) {
Console.WriteLine("Exception handled here."); }
public void DangerousFunc4( ) {
throw new DivideByZeroException("E1 - DivideByZero Exception"); }
} }
Kết quả:
E3 - Custom Exception Situation! Retrieving exception history... E2 - Func2 caught divide by zero E1 - DivideByZeroException
Ghi chú: Kết quả xuất hiện trên màn hình không đủ để thể hiện hết ý, cách tốt nhất là nên chạy chương trìnhở chếđộ từng dòng lệnh để hiểu rõ vấnđề hơn.
Chúng ta bắt đầu bằng lời gọi hàm DangerousFunc1() trong khối try try
{
DangerousFunc1( ); }
DangerousFunc1() gọi DangerousFunc2(), DangerousFunc2() gọi DangerousFunc3(), DangerousFunc3() gọi DangerousFunc4(). Tất cả các lời gọi này đều có khối try của riêng nó. Cuối cùng DangerousFunc4() ném một biệt lệ
DivideByZeroException với câu thông báo E1 – DivideByZero Exception.
Khối lệnh catch trong hàm DangerousFunc3() sẽ bắt biệt lệ này. Theo logic, tất cả các lỗi toán học đều được bắt bởi biệt lệ ArithmeticException (vì vậy cả
DivideByZeroException). Nó chẳng làm gì, chỉ ném biệt lệ này lần nữa. catch (System.ArithmeticException)
{ throw; }
Cú pháp trên ném cùng một loại biệt lệ cho khối try bên ngoài (chỉ cần từ khóa throw) DangerousFunc2() sẽ bắt được biệt lệ này, nó sẽ ném ra một biệt lệ mới thuộc kiểu Exception. Khi khởi tạo biệt lệ này, ta truyền cho nó hai tham số: thông báo E2 - Func2 caught divide by zero, và biệt lệ cũđể làm biệt lệ nội.
DangerousFunc1() bắt biệt lệ này, làm vài công việc nào đó, sau đó tạo một biệt lệ có kiểu MyCustomException. Tương tự như trên khi khởi tạo biệt lệ ta truyền cho nó hai tham số: thông báo E3 - Custom Exception Situation!, và biệt lệ
vừa bắt được làm biệt lệ nội. Đến thời điểm này biệt lệđã có hai mức biệt lệ nội. Cuối cùng, khối catch sẽ bắt biệt lệ này và in thông báo E3 - Custom Exception Situation!
Sau đó sẽ tiếp tục in các thông báo của các biệt lệ nội while (inner != null)
Console.WriteLine("{0}",inner.Message); inner = inner.InnerException;
}
Và ta có kết quả
Retrieving exception history... E2 - Func2 caught divide by zero E1 - DivideByZero Exception