Trong ví dụ này, hơn là việc đơn giản phát sinh một DidiveByZeroException, chúng ta tạo một thể hện mới của ngoại lệ: DivideByZeroException e = new DivideByZeroException; Chúng ta không
Trang 1-
Kết quả:
Open file here
DivideByZeroExceptión Msg: Attempted to divide by zero
HelpLink: http://www.hcmuns.edu.vn
Here’s a stack trace:
at Programming_CSharp.Test.DoDivide(Double c, Double b)
in c:\ exception06.cs: line 56
at Programming_CSharp.Test.TestFunc() in exception06.cs: line 22 Close file
here
-Trong đoạn kết quả trên, danh sách trace của stack được hiển thị theo thứ tự ngược lại thứ tự gọi Nó hiển thị một lỗi trong phương thức DoDivde(), phương thức này được gọi từ phương thức TestFunc() Khi các phương thức gọi lồng nhau nhiều cấp, thông tin stack có thể giúp chúng ta hiểu thứ tự của các phương thức được gọi
Trong ví dụ này, hơn là việc đơn giản phát sinh một DidiveByZeroException, chúng
ta tạo một thể hện mới của ngoại lệ:
DivideByZeroException e = new DivideByZeroException();
Chúng ta không truyền vào thông điệp của chúng ta, nên thông điệp mặc định sẽ được
in ra:
DivideByZeroException! Msg: Attemped to divide by zero
Ở đây chúng ta có thể bổ sung như dòng lệnh bên dưới để truyền vào thông điệp của chúng ta tùy chọn như sau:
new DivideByZeroException(“You tried to divide by zero which is not
meaningful”);
Trước khi phát sinh ra ngoại lệ, chúng ta thiết lập thuộc tính HelpLink như sau:
e.HelpLink = “http://www.hcmunc.edu.vn”;
Khi ngoại lệ được bắt giữ, chương trình sẽ in thông điệp và HelpLink ra màn hình: catch (System.DivideByZeroException e)
{
Console.WriteLine(“\nDivideByZeroException! Msg: {0}”,
e.Message); Console.WriteLine(“\nHelpLink: {0}”, e.HelpLink);
}
Việc làm này cho phép chúng ta cung cấp những thông tin hữu ích cho người sử dụng Thêm vào đó thông tin stack cũng được đưa ra bằng cách sử dụng thuộc tính StackTrace của đối tượng ngoại lệ:
Console.WriteLine(“\n Here’s a stack trace: {0}\n”, e.StackTrace);
Kết quả là các vết trong stack sẽ được xuất ra:
Trang 2Here’s a stack trace:
at Programming_CSharp.Test.DoDivide(Double c, Double b)
Trang 3in c:\ exception06.cs: line 56
at Programming_CSharp.Test.TestFunc() in exception06.cs: line 22
Lưu ý rằng, phần đường dẫn được viết tắt, do đó kết quả của bạn có thể hơi khác một tí Bảng 13.1 sau mô tả một số các lớp ngoại lệ chung được khai báo bên trong namespace
System
CÁC LỚP NGOẠI
LỆ
MethodAccessException Lỗi truy cập, do truy cập đến thành viên
hay phương thức không được truy cập ArgumentException Lỗi tham số đối mục
ArgumentNullException Đối mục Null, phương thức được truyền đối
mục null không được chấp nhận ArithmeticException Lỗi liên quan đến các phép toán
ArrayTypeMismatchException Kiểu mảng không hợp, khi cố lưu trữ kiểu
không thích hợp vào mảng DivideByZeroException Lỗi chia zero
FormatException Định dạng không chính xác một đối mục nào đó IndexOutOfRangeException Chỉ số truy cập mảng không hợp lệ, dùng nhỏ
hơn chỉ số nhỏ nhất hay lớn hơn chỉ số lớn nhất của mảng
InvalidCastException Phép gán không hợp lệ
MulticastNotSupportedException Multicast không được hỗ trợ, do việc kết hợp
hai delegate không đúng NotFiniteNumberException Không phải số hữu hạn, số không hợp lệ
NotSupportedException Phương thức không hỗ trợ, khi gọi một
phương thức không tồn tại bên trong lớp
NullReferenceException Tham chiếu null không hợp lệ
OutOfMemoryException Out of memory
OverflowException Lỗi tràn phép toán
StackOverflowException Tràn stack
TypeInitializationException Kiểu khởi tạo sai, khi bộ khởi dựng tĩnh có lỗi
Trang 4Bảng 13.1 : Các ngoại lệ thường xuất hiện
Tạo riêng các ngoại lệ
CLR cung cấp những kiểu dữ liệu ngoại lệ cơ bản, trong ví dụ trước chúng ta đã tạo một vài các kiểu ngoại lệ riêng Thông thường chúng ta cần thiết phải cung cấp các thông tin
mở rộng cho khối catch khi một ngoại lệ được phát sinh Tuy nhiên, có những lúc
chúng ta muốn cung cấp nhiều thông tin mở rộng hay là các khả năng đặc biệt cần thiết trong ngoại lệ mà chúng ta tạo ra Chúng ta dễ dàng tạo ra các ngoại lệ riêng, hay còn gọi
là các ngoại lệ tùy chọn (custom exception), điều bắt buộc với các ngoại lệ này là chúng phải được dẫn xuất từ System.ApplicationException Ví dụ 13.7 sau minh họa việc tạo một ngoại lệ riêng
Ví dụ: Tạo một ngoại lệ riêng
-
namespace Programming_CSharp
{
using System;
// tạo ngoại lệ riêng
public class MyCustomException : System.ApplicationException
{
public MyCustomException( string message): base(message)
{
}
}
public class Test
{
public static void Main()
{
Test t = new Test();
t.TestFunc();
}
// chia hai số và xử lý ngoại lệ
public void TestFunc()
{
try {
}
Console.WriteLine(“Open file here”);
double a = 0;
double b = 5;
Console.WriteLine(“{0} /{1} = {2}”, a, b, DoDivide(a,b)); Console.WriteLine(“This line may or not print”);
Trang 5catch (System.DivideByZeroException e)
{
Console.WriteLine(“\nDivideByZeroException! Msg: {0}”, e.Message); Console.WriteLine(“\nHelpLink: {0}”, e.HelpLink);
}
catch (MyCustomException e)
{
Console.WriteLine(“\nMyCustomException! Msg: {0}”, e.Message); Console.WriteLine(“\nHelpLink: {0}”, e.HelpLink);
}
catch
{
Console.WriteLine(“Unknown excepiton caught”);
}
finally
{
Console.WriteLine(“Close file here.”);
}
}
// thực hiện phép chia hợp lệ
public double DoDivide( double a, double b)
{
if ( b == 0)
{
DivideByZeroException e = new DivideByZeroException();
e.HelpLink = “http://www.hcmunc.edu.vn”;
throw e;
}
if ( a == 0)
{
divisor”);
}
MyCustomException e = new MyCustomException(“Can’t have zero
e.HelpLink = “http://www.hcmuns.edu.vn”;
throw e;
return a/b;
}
}
Trang 6
-Lớp MyCustomException được dẫn xuất từ System.ApplicationException và lớp này không
có thực thi hay khai báo gì ngoài một hàm khởi dựng Hàm khởi dựng này lấy tham số là một chuỗi và truyền cho lớp cơ sở Trong trường hợp này, lợi ích của việc tạo ra ngoại
lệ là làm nổi bật điều mà chuơng trình muốn minh họa, tức là không cho phép số chia là zero Sử dụng ngoại lệ ArithmeticException thì tốt hơn là ngoại lệ chúng ta tạo ra Nhưng nó có thể làm nhầm lẫn cho những người lập trình khác vì phép chia với số chia
là zero không phải là lỗi số học
Phát sinh lại ngoại lệ
Giả sử chúng ta muốn khối catch thực hiện một vài hành động đúng nào đó rồi sau đó phát sinh lại ngoại lệ ra bên ngoài khối catch (trong một hàm gọi) Chúng ta
được phép phát sinh lại cùng một ngoại lệ hay phát sinh lại các ngoại lệ khác Nếu phát sinh ra ngoại lệ khác, chúng ta có thể phải nhúng ngoại lệ ban đầu vào bên trong ngoại lệ mới để phương thức gọi
có thể hiểu được lai lịch và nguồn gốc của ngoại lệ Thuộc tính InnerException của ngoại lệ mới cho phép truy cập ngoại lệ ban đầu
Bởi vì InnerException cũng là một ngoại lệ, nên nó cũng có một ngoại lệ bên trong
Do vậy, toàn bộ dây chuyền ngoại lệ là một sự đóng tổ (nest) của một ngoại lệ này với một ngoại lệ khác Giống như là con lật đật, mỗi con chứa trong một con và đến lượt con bên trong lại chứa
Ví dụ 13.8: Phát sinh lại ngoại lệ & ngoại lệ inner
-
namespace Programming_CSharp
{
using System;
// tạo ngoại lệ riêng
public class MyCustomException : System.Exception
{
public MyCustomException( string message, Exception inner):
base(message, inner)
{
}
}
public class Test
{ public static void Main()
Trang 7{
Test t = new Test();
Trang 8t.TestFunc();
}
// chia hai số và xử lý ngoại lệ
public void TestFunc()
{
try {
}
DangerousFunc1();
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();
catch (System.Exception e)
{
MyCustomException ex = new MyCustomException(“E3 – Custom Exception Situation”, e);
throw ex;
}
}
public void DangerousFunc2()
{
Trang 10DangerousFunc3();
}
catch (System.DivideByZeroException e)
{
Exception ex = new Exception(“E2 - Func2 caught divide by zero”, e);
throw ex;
}
}
public void DangerousFunc3()
{
try {
}
DangerousFunc4();
Trang 11catch (System.ArithmeticException)
{
throw;
}
catch (System.Exception)
{
Console.WriteLine(“Exception handled here.”);
}
}
public void DangerousFunc4()
{
throw new DivideByZeroException(“E1 – DivideByZero Exception”); }
}
}