Ngôn Ngữ Lập Tnh C#
{
public static void Main()
{
Test t = new Test();
t.TestFunc();
}
// ta thử chia hai phần xử lý ngoại lệ riêng
public void TestFunc()
{
try
{
double a = 5;
double b = 0;
Console.WriteLine(“{0} / {1} = {2}”, a, b, DoDivide(a,b));
}
catch (System.DivideByZeroException)
{
Console.WriteLine(“DivideByZeroException caught!”);
}
catch (System.ArithmeticException)
{
Console.WriteLine(“ArithmeticException caught!”);
}
catch
{
Console.WriteLine(“Unknown exception caught”);
}
}
// thực hiện phép chia hợp lệ
public double DoDivide(double a, double b)
{
if ( b == 0)
throw new System.DivideByZeroException();
if ( a == 0)
throw new System.ArithmeticException();
return a/b;
}
}
X Ngoại Lệ
372
Giáo trình hình thành công thức điều chỉnh
testfunc khi thực hiện chia với zero
.
Ngôn Ngữ Lập Tnh C#
}
-----------------------------------------------------------------------------
Kết quả:
DivideByZeroException caught!
-----------------------------------------------------------------------------
Trong dụ này, phương thức DoDivide() sẽ không cho phép chúng ta chia cho zero bởi một
số khác, cũng không cho phép chia số zero. sẽ phát sinh một đối tượng của Divide-
ByzeroException nếu chúng ta thực hiện chia với zero. Trong toán học việc lấy zero chia cho
một số khác được phép, nhưng trong dụ minh họa của chúng ta không cho phép thực
hiện việc này, nếu thực hiện sẽ phát sinh ra một ngoại lệ ArithmeticException.
Khi một ngoại lệ được phát sinh, CLR sẽ kiểm tra mỗi khối xử ngoại lệ theo thứ tự sẽ
lấy khối đầu tiên thích hợp. Khi chúng ta thực hiện với a=5b=7 thì kết quả như sau:
5 / 7 = 0.7142857142857143
Như chúng ta mong muốn, không ngoại lệ được phát sinh. Tuy nhiên, khi chúng ta thay
đổi giá trị của a là 0, thì kết quả là:
ArithmeticException caught!
Ngoại lệ được phát sinh, CLR sẽ kiểm tra ngoại lệ đầu tiên: DivideByZeroException. Bởi
vì không phù hợp, nên nó sẽ tiếp tục đi tìm và khối xử lý ArithmeticException được chọn.
Cuối cùng, giả sử chúng ta thay đổi giá trị của b là 0. Khi thực hiện điều y sẽ dẫn đến ngoại
lệ DivideByZeroException.
Ghi chú: Chúng ta phải cẩn thận thứ tự của câu lệnh catch, bởi DivideByZero-
Exception được dẫn xuất từ ArithmeticException. Nếu chúng ta đảo thứ tự của câu lệnh
catch, thì ngoại lệ DivideByZeroException sẽ được phù hợp với khối xử ngoại lệ Arith-
meticException. việc xử ngoại lệ sẽ không bao giờ được giao cho khối xử
DivideByZeroException. Thật vậy, nếu thứ tự này được đảo, sẽ không cho phép bất cứ
ngoại lệ nào được xử lý bởi khối xử lý ngoại lệ DivideByZeroException. Trình biên dịch sẽ
nhận ra rằng DivideByZeroException không được thực hiện bất cứ khi nào sẽ thông
báo một lỗi biên dịch.
Chúng ta thể phân phối câu lệnh try/ catch, bằng cách bắt giữ những ngoại lệ xác định
trong một hàm nhiều ngoại lệ tổng quát trong nhiều hàm. Mục đích của thực hiện này
đưa ra các thiết kế đúng. Giả sử chúng ta có phương thức A, phương thức này gọi một phương
thức khác tên là phương thức B, đến lượt mình phương thức B gọi phương thức C. Và phương
thức C tiếp tục gọi phương thức D, cuối cùng phương thức D gọi phương thức E. Phương thức
E mức độ sâu nhất trong chương trình của chúng ta, phương thức A, B mức độ cao hơn.
Nếu chúng ta đoán trước phương thức E thể phát sinh ra ngoại lệ, chúng ta thể tạo ra
khối try/catch để bắt giữ những ngoại lệ này ở chỗ gần nơi phát sinh ra ngoại lệ nhất. Chúng
ta cũng thể tạo ra nhiều khối xử ngoại lệ chung trong đoạn chương trình mức cao
trong trường hợp những ngoại lệ không đoán trước được.
X Ngoại Lệ
373
.
.
Ngôn Ngữ Lập Tnh C#
Câu lệnh finally
Trong một số tình huống, việc phát sinh ngoại lệ và unwind stack có thể tạo ra một số vấn
đề. dụ như nếu chúng ta mở một tập tin hay trường hợp khác xác nhận một tài nguyên,
chúng ta thể cần thiết một hội để đóng một tập tin hay giải phóng bộ nhớ đệm
chương trình đã chiếm giữ trước đó.
Ghi chú: Trong ngôn ngữ C#, vấn đề này ít xảy ra hơn do chế thu dọn tự động của C#
ngăn ngừa những ngoại lệ phát sinh từ việc thiếu bộ nhớ.
Tuy nhiên, có một số hành động mà chúng ta cần phải quan tâm bất cứ khi nào một ngoại
lệ được phát sinh ra, như việc đóng một tập tin, chúng ta hai chiến lược để lựa chọn thực
hiện. Một hướng tiếp cận là đưa hành động nguy hiểm vào trong khối try và sau đó thực hiện
việc đóng tập tin trong cả hai khối catch try. Tuy nhiên, điều này gây ra đoạn chương
trình không được đẹp do sdụng trùng lắp lệnh. Ngôn ngữ C# cung cấp một sự thay thế tốt
hơn trong khối finally.
Đoạn chương trình bên trong khối catch được đảm bảo thực thi không quan tâm đến
việc khi nào thì một ngoại lệ được phát sinh. Phương thức TestFunc() trong dụ 13.5 minh
họa việc mở một tập tin như là hành động đầu tiên của nó, sau đó phương thức thực hiện một
vài các phép toán toán học, sau đó tập tin được đóng. thể trong quá trình mở tập tin
cho đến khi đóng tập tin chương trình phát sinh ra một ngoại lệ. Nếu xuất hiện ngoại lệ,
khi đó tập tin vẫn còn mở. Người phát triển biết rằng không chuyện xảy ra, cuối của
phương thức này thì tập tin sẽ được đóng. Do chức năng đóng tập tin được di chuyển vào
trong khối finally, đây sẽ được thực thi không cần quan tâm đến việc phát sinh
hay không một ngoại lệ trong chương trình.
Ví dụ 13.5: Sử dụng khối finally.
-----------------------------------------------------------------------------
namespace Programming_CSharp
{
using System;
public class Test
{
public static void Main()
{
Test t = new Test();
t.TestFunc();
}
// chia hai số và xử lý ngoại lệ nếu có
public void TestFunc()
{
try
X Ngoại Lệ
374
.
.
Ngôn Ngữ Lập Tnh C#
{
Console.WriteLine(“Open file here”);
double a = 5;
double b = 0;
Console.WriteLine(“{0} /{1} = {2}”, a, b, DoDivide(a,b));
Console.WriteLine(“This line may or not print”);
}
catch (System.DivideByZeroException)
{
Console.WriteLine(“DivideByZeroException caught!”);
}
catch
{
Console.WriteLine(“Unknown exception caught”);
}
finally
{
Console.WriteLine(“Close file here.”);
}
}
// thực hiện chia nếu hợp lệ
public double DoDivide(double a, double b)
{
if ( b == 0)
{
throw new System.DivideByZeroException();
}
if ( a == 0)
{
throw new System.ArithmeticException();
}
return a/b;
}
}
}
-----------------------------------------------------------------------------
Kết quả:
Open file here
X Ngoại Lệ
375
.
.
Ngôn Ngữ Lập Tnh C#
DivideByZeroException caught!
Close file here.
Kết quả trong trường hợp b = 12
Open file here
5/ 12 = 0.416666666666
Close file here
-----------------------------------------------------------------------------
Trong ví dụ này một khối catch được loại bỏ và thêm vào khối finally. Bất cứ khi một ngoại
lệ có được phát sinh ra hay không thì khối lệnh bên trong finally cũng được thực thi. Do vậy
nên trong cả hai trường hợp ta cũng thấy xuất hiện thông điệp “Close file here”.
Những đối tượng ngoại lệ
Cho đến lúc này thì chúng ta thể sử dụng tốt các ngoại lệ cũng như cách xử khắc
phục các ngoại lệ này. Trong phần này chúng ta sẽ tiến hành việc tìm hiểu các đối tượng được
xây dựng cho việc xử ngoại lệ. Đối tượng System.Exception cung cấp một số các phương
thức và thuộc tính hữu dụng. Thuộc tính Message cung cấp thông tin về ngoại lệ, như là lý do
tại sao ngoại lệ được phát sinh. Thuộc tính Messagethuộc tính chỉ đọc, đoạn chương trình
phát sinh ngoại lệ thể thiết lập thuộc tính Message như một đối mục cho bộ khởi dựng
của ngoại lệ. Thuộc tính HelpLink cung cấp một liên kết để trợ giúp cho các tập tin liên quan
đến các ngoại lệ. Đây thuộc tính chỉ đọc. Thuộc tính StackTrace cũng là thuộc tính chỉ đọc
được thiết lập bởi CLR. Trong ví dụ 13.6 thuộc tính Exception.HelpLink được thiết lập
truy cập để cung cấp thông tin cho người sử dụng về ngoại lệ DivideBy-ZeroException.
Thuộc tính StackTrace của ngoại lệ được sử dụng để cung cấp thông tin stack cho câu lệnh
lỗi. Một thông tin stack cung cấp hàng loạt các cuộc gọi stack của phương thức gọi dẫn
đến những ngoại lệ được phát sinh.
Ví dụ 13.6: Làm việc với đối tượng ngoại lệ.
-----------------------------------------------------------------------------
namespace Programming_CSharp
{
using System;
public class Test
{
public static void Main()
{
Test t = new Test();
t.TestFunc();
}
// chia hai số và xử lý ngoại lệ
X Ngoại Lệ
376
.