Tài liệu Tìm hiểu C# và ứng dụng của C# p 13 - Pdf 98

Quản lý lỗi Gvhd: Nguyễn Tấn Trần Minh Khang
72 Chương 11 Quản lý lỗi
C# quản lý lỗi và các trạng thái bất thường bằng biệt lệ (exception). Một biệt lệ là
một đối tượng chứa các thông tin về sự cố bất thường của chương trình.
Điều quan trọng trước hết là phải phân biệt rõ sự khác nhau giữa bug, error và biệt
lệ. Bug là lỗi về mặt lập trình do chính lập trình viên không kiểm soát được mã
nguồn. Biệt lệ không thể sửa các bug. Mặc dù bug sẽ phát sinh (ném) một biệt lệ,
chúng ta không nên dựa vào các biệt lệ để sửa các bug, mà nên viết lại mã nguồn
cho đúng.
Error là lỗi gây ra bởi người dùng. Chẳng hạn như người dùng nhập một con số thay
vì phải nhập các ký tự chữ cái. Một error cũng ném ra một biệt lệ, nhưng ta có thể
ngăn chặn bằng cách bắt lấy lỗi này, yêu cầu người dùng chỉnh sửa cho đến khi hợp
lệ. Bất cứ khi nào có thể, error nên được tiên đoán trước và ngăn chặn.
Ngay cả khi các bug đã được sửa, các error đã được tiên đoán hết thì vẫn còn nhiều
tình huống không thể lường trước như: hệ thống đã hết bộ nhớ hay chương trình
đang truy cập một tập tin không tồn tại…. Chúng ta không thể ngăn chặn được biệt
lệ nhưng có lại có thể quản lý được chúng để chúng không làm gẫy đỗ ứng dụng.
Khi chương trình gặp phải tình huống trên, chẳng hạn hết bộ nhớ, nó sẽ ném (phát
sinh) một biệt lệ. Khi một biệt lệ được ném ra, hàm đang thực thi sẽ bị tạm dừng và
vùng nhớ stack sẽ được duyệt ngược cho đến khi gặp trình giải quyết biệt lệ.
Điều này có nghĩa là nếu hàm hiện hành không có trình giải quyết biệt lệ thì hàm sẽ
bị ngắt và hàm gọi sẽ có cơ hội để giải quyết lỗi. Nếu không có hàm gọi nào giải
quyết biệt lệ thì biệt lệ sẽ được ném cho CLR giải quyết. Điều này đồng nghĩa với
việc chương trình sẽ bị dừng một cách bất thường.
Trình quản lý lỗi (exception handler) là một đoạn mã được thiết kế để giải quyết các
biệt lệ được ném ra. Trình giải quyết lỗi được cài đặt trong khối lệnh bắt đầu bởi từ
khóa
catch{}. Một cách lý tưởng thì khi biệt lệ được bắt và giải quyết thì chương

Exception
và sau đó ném nó ra
throw new System.Exception();
Ném một biệt lệ sẽ làm chương trình tạm dừng lập tức và CLR tìm kiếm một trình
quản lý biệt lệ. Nếu hàm ném không có trình giải quyết biệt lệ,
stack
sẽ được
duyệt ngược (
unwind
) bằng cách
pop
ra cho đến khi gặp được trình giải quyết biệt
lệ. Nếu vẫn không tìm thấy cho đến tận hàm
Main()
, chương trình sẽ bị dừng lại.
Ví dụ 11-1. Ném một biệt lệ
using System;
namespace Programming_CSharp
{
public class Test
{
public static void Main( )
{
Console.WriteLine("Enter Main ");
Test t = new Test( );
t.Func1( );
Console.WriteLine("Exit Main ");
}
public void Func1( )
{

Main()
tạo một đối tượng kiểu
Test
và gọi hàm
Func1().
Sau khi in thông
báo
Enter Func1
, hàm
Func1()
gọi hàm
Func2().

Func2()
in ra câu thông
báo bắt đầu và ném ra một biệt lệ.
Chương trình sẽ tạm ngưng thực thi và CLR tìm trình giải quyết biệt lệ trong hàm
Func2().
Không có, vùng nhớ
stack
được
unwind
cho đến hàm
Func1().
Vẫn
không có, vùng nhớ
stack
tiếp tục được
unwind
cho đến hàm

public void Func1( )
{
Console.WriteLine("Enter Func1 ");
Func2( );
Console.WriteLine("Exit Func1 ");
}
public void Func2( )
{
Console.WriteLine("Enter Func2 ");
try
{
Console.WriteLine("Entering try block ");
throw new System.Exception( );
Console.WriteLine("Exiting try block ");
}
catch
{
Quản lý lỗi Gvhd: Nguyễn Tấn Trần Minh Khang
75
Console.WriteLine(
"Exception caught and handled.");
}
Console.WriteLine("Exit Func2 ");
}
}
}
Kết quả:
Enter Main
Enter Func1
Enter Func2

ở đây. Ví dụ nếu người dùng cố mở một tập chỉ đọc, ta hẳn cho gọi một phương
thức cho phép người dùng thay đổi thuộc tính tập tin. Nếu trường hợp hết bộ nhớ, ta
hẳn cho người dùng cơ hội đóng các ứng dụng khác. Nếu tất cả đều thất bại, khối
lệnh
catch sẽ cho in các thông báo mô tả chi tiết lỗi để người dùng biết rõ vấn đề.
11.1.2.2 Duyệt lại (unwind) vùng nhớ stack
Nếu xem kết quả ví dụ 11-2 cẩn thận, ta sẽ thấy các thông báo bắt đầu hàm
Main(), Func1(), Func2()
và khối lệnh
try
; tuy nhiên lại không thấy thông
báo kết thúc khối
try mặc dù nó đã thoát khỏi hàm
Func2(), Func1()
và hàm
Main().
Khi một biệt lệ xảy ra, khối
try ngừng thực thi ngay lập tức và quyền được trao cho
khối lệnh
catch
. Nó sẽ không bao giờ quay trở lại khối
try
và vì thế không thể in
dòng lệnh thoát khối
try
. Sau khi hoàn tất khối lệnh
catch
, các dòng lệnh sau
khối
catch

{
Console.WriteLine("Enter Func1 ");
try
{
Console.WriteLine("Entering try block ");
Func2( );
Console.WriteLine("Exiting try block ");
}
catch
{
Console.WriteLine( "Exception caught and handled." );
}
Console.WriteLine("Exit Func1 ");
}
public void Func2( )
{
Console.WriteLine("Enter Func2 ");
throw new System.Exception( );
Console.WriteLine("Exit Func2 ");
}
}
}
Kết quả:
Enter Main
Enter Func1
Entering try block
Enter Func2
Exception caught and handled.
Exit Func1
Exit Main

của
Func1()
và sau đó là của
Main().
Dòng
Exit Try Block
và dòng
Exit
Func2
không được in.
11.1.2.3 Tạo một lệnh catch chuyên dụng
Ta có thể tạo một lệnh
catch
chuyên dụng quản lý một loại biệt lệ. Ví dụ 11-4 mô
tả cách xác định loại biệt lệ nào ta nên quản lý.
Ví dụ 11-4. Xác định biệt lệ phải bắt
using System;
namespace Programming_CSharp
{
public class Test
{
public static void Main( )
{
Test t = new Test( );
t.TestFunc( );
}
// thử chia hai số
// và giải quyết các biệt lệ
public void TestFunc( )
{

}
}

Quản lý lỗi Gvhd: Nguyễn Tấn Trần Minh Khang
78
Kết quả:
DivideByZeroException caught!
Trong ví dụ này,
DoDivide()
sẽ không cho phép chia một số cho 0 hay chia 0 cho
số khác. Nó sẽ ném ra biệt lệ
DivideByZeroException
nếu ta cố chia cho
không. Nếu ta đem chia 0 cho số khác, sẽ không có biệt lệ thích hợp: vì chia không
cho một số là một phép toán hợp lệ và không nên ném bất kỳ biệt lệ nào. Tuy nhiên
giả sử trong ví dụ này ta không muốn đem 0 chia cho số khác và sẽ ném ra biệt lệ
ArithmeticException
.
Khi một biệt lệ được ném ra, CLR tìm kiếm trình giải quyết biệt lệ theo theo trình
tự, và chọn trình giải quyết phù hợp với biệt lệ. Khi chạy chương trình với
a = 5


b = 7
, kết quả là:
5 / 7 = 0.7142857142857143
Không có biệt lệ nào phát sinh. Tuy nhiên nếu thay
a = 0
, kết quả sẽ là:
ArithmeticException caught!

quyết được nếu ta quyết định không viết khối
catch
ở hàm này mà giao cho hàm
gọi xử lý. Khi đó không thể viết lệnh đóng tập tin.
Cách viết đẹp nhất là trong khối
finally
. Khối lệnh này chắc chắn được gọi cho
dù có hay không có xảy ra biệt lệ. Ví dụ 11-5 chứng minh cho điều này
Quản lý lỗi Gvhd: Nguyễn Tấn Trần Minh Khang
79
Ví dụ 11-5. Sử dụng khối lệnh finally
using System;
namespace Programming_CSharp
{
public class Test
{
public static void Main( )
{
Test t = new Test( );
t.TestFunc( );
}
// thử chia hai số
// và giải quyết các biệt lệ
public void TestFunc( )
{
try
{
Console.WriteLine("Open file here");
double a = 5;
double b = 0;

Open file here
DivideByZeroException caught!
Close file here.
Output when b = 12:
Open file here
5 / 12 = 0.41666666666666669
This line may or may not print
Close file here.
Quản lý lỗi Gvhd: Nguyễn Tấn Trần Minh Khang
80
Trong ví dụ này dòng thông báo Close file here luôn luôn xuất hiện, cho dù biệt
lệ có xảy ra hay không.
Ghi chú: khối lệnh
finally có thể được tạo mà không cần khối catch,
nhưng bắt buộc phải có khối
try. Không thể dùng các lệnh break,
continue, return và goto trong khối finally.


Nhờ tải bản gốc

Tài liệu, ebook tham khảo khác

Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status