1. Trang chủ
  2. » Công Nghệ Thông Tin

Những đối tượng ngoại lệ

19 151 0

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 19
Dung lượng 121,66 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

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 mà dẫn đến những ngoại lệ được phát sinh.. Trong ví dụ này, hơn là việc đơn giản phát sinh một DidiveByZeroE

Trang 1

Những đối tượng ngoại lệ

Bởi:

Khuyet Danh

Đố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 Message là thuộc tính chỉ đọc, đoạn chương trình phát sinh ngoại

lệ có thể thiết lập thuộc tính Message như là 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 là thuộc tính chỉ đọc Thuộc tính StackTrace cũng là thuộc tính chỉ đọc và được thiết lập bởi CLR Trong ví dụ 13.6 thuộc tính Exception.HelpLink được thiết lập và 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 mà dẫn đến những ngoại lệ được phát sinh

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();

Trang 2

// chia hai số và xử lý ngoại lệ

public void TestFunc()

{

try

{

Console.WriteLine("Open file here");

double a = 12;

double b = 0;

Console.WriteLine("{0} /{1} = {2}", a, b, DoDivide(a,b)); Console.WriteLine("This line may or not print");

}

catch (System.DivideByZeroException e)

{

Console.WriteLine("\nDivideByZeroException! Msg: {0}",

e.HelpLink);

Console.WriteLine("\nHere’s a stack trace: {0}\n", e.StackTrace);

}

catch

{

Console.WriteLine("Unknown exception caught");

Trang 3

}

// 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)

{

throw new ArithmeticException();

}

return a/b;

}

}

}

-Kết quả:

Open file here

Trang 4

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)

{

Trang 5

Console.WriteLine("\nDivideByZeroException! Msg: {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:

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

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 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 ngoại lệ thường xuất hiện CÁC LỚP NGOẠI LỆ

MethodAccessException Lỗi truy cập, do truy cập đến thành viên

hayphươ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 đốimụcnull 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ểukhôngthích hợp vào mảng

Trang 6

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ủamả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

haidelegate 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ươngthứ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

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 catchkhi 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ụ sau minh họa việc tạo một ngoại lệ riêng

Tạo một ngoại lệ riêng

-namespace Programming_CSharp

{

Trang 7

using System;

// tạo ngoại lệ riêng

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");

Trang 8

double a = 0;

double b = 5;

Console.WriteLine("{0} /{1} = {2}", a, b, DoDivide(a,b)); Console.WriteLine("This line may or not print");

}

catch (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.HelpLink);

}

catch

{

Console.WriteLine("Unknown excepiton caught");

}

finally

{

Trang 9

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." n";

throw e;

}

if ( a == 0)

{

MyCustomException e = new MyCustomException("Can’t have zero divisor");

e.HelpLink = "http://www.hcmuns.edu.vn" ;

throw e;

}

return a/b;

}

}

Trang 10

-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

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):

Trang 11

base(message, inner)

{

}

}

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

{

DangerousFunc1();

}

catch (MyCustomException e)

{

Console.WriteLine("\n{0}", e.Message);

Trang 12

Console.WriteLine("Retrieving exception history "); Exception inner =e.InnerException;

while ( inner != null)

{

Console.WriteLine("{0}", inner.Message);

inner = inner.InnerException;

}

}

}

{

try

{

DangerousFunc2();

}

MyCustomException ex = new

MyCustomException("E3 - Custom Exception Situation", e); throw ex;

}

}

public void DangerousFunc2()

{

try

Trang 13

DangerousFunc3();

}

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)

{

Trang 14

Console.WriteLine("Exception handled here.");

}

}

public void DangerousFunc4()

{

Exception");

}

}

}

-Kết quả:

E3 – Custom Exception Situation!

Retrieving exception history

E2 - Func2 caught divide by zero

E1 – DivideByZeroException

-Để hiểu rõ hơn ta có thể dùng trình debugger để chạy từng bước chương trình khi đó ta

sẽ hiểu rõ từng bước thực thi cũng như việc phát sinh các ngoại lệ

Chương trình bắt đầu với việc gọi hàm DangerousFunc1() trong khối try:

try { DangerousFunc1(); }

DangerousFunc1() gọi DangerousFunc2(), DangerousFunc2() lại gọi DangerousFunc3(), và cuối cùng DangerousFunc3() gọi DangerousFunc4() Tất cả việc gọi này điều nằm trong khối try Cuối cùng, DangerousFunc4() phát sinh ra ngoại lệ DivideByzeroException Ngoại lệ này bình thường có chứa thông điệp bên trong nó,

Trang 15

nhưng ở đây chúng ta tự do dùng thông điệp mới Để dễ theo dõi chúng ta đưa vào các chuỗi xác nhận tuần tự các sự kiện diễn ra

Ngoại lệ được phát sinh trong DangerousFunc4() và nó được bắt trong khối catch trong hàm DangerousFunc3() Khối catch trong DangerousFunc3() sẽ bắt các ngoại lệ Arithmetic- Exception ( như là DivideByZeroException), nó không thực hiện hành động nào mà chỉ đơn giản là phát sinh lại ngoại lệ:

catch ( System.ArithmeticException) { throw; }

Cú pháp để thực hiện phát sinh lại cùng một ngoại lệ mà không có bất cứ bổ sung hay hiệu chỉnh nào là : throw

Do vậy ngoại lệ được phát sinh cho DangerousFunc2(), khối catch trong DangerousFunc2() thực hiện một vài hành động và tiếp tục phát sinh một ngoại lệ có kiểu mới Trong hàm khởi dựng của ngoại lệ mới, DangerousFunc2() truyền một chuỗi thông điệp mới (“E2 - Func2 caught divide by zero”) và ngoại lệ ban đầu Do vậy ngoại lệ ban đầu (E1) trở thành ngoại lệ bên trong của ngoại lệ mới (E2) Sau đó hàm DangerousFunc2() phát sinh ngoại lệ này (E2) cho hàm DangerousFunc1()

DangerousFunc1() bắt giữ ngoại lệ này, làm một số công việc và tạo ra một ngoại lệ mới

có kiểu là MyCustomException, truyền vào hàm khởi dựng của ngoại lệ mới một chuỗi mới (“E3 – Custom Exception Situation!”) và ngoại lệ được bắt giữ (E2) Chúng ta nên nhớ rằng ngoại lệ được bắt giữ là ngoại lệ có chứa ngoại lệ DivideByZeroException (E1) bên trong nó Tại thời điểm này, chúng ta có một ngoại lệ kiểu MyCustomException (E3), ngoại lệ này chứa bên trong một ngoại lệ kiểu Exception (E2), và đến lượt nó chứa một ngoại lệ kiểu DivideByZeroException (E1) bên trong Sau cùng ngoại lệ được phát sinh cho hàm TestFunc;

Khi khối catch của TestFunc thực hiện nó sẽ in ra thông điệp của ngoại lệ :

E3 – Custom Exception Situation!

sau đó từng ngoại lệ bên trong sẽ được lấy ra thông qua vòng lặp while:

while ( inner != null) { Console.WriteLine("{0}",

inner.Message); inner = inner.InnerException; }

Kết quả là chuỗi các ngoại lệ được phát sinh và được bắt giữ:

Retrieving exception history

E2 - Func2 caught divide by zero E1 – DivideByZero Exception

Trang 16

Câu hỏi và câu trả lời

Câu hỏi và trả lời

Việc sử dụng catch không có tham số có vẻ như có nhiều sức mạnh do chúng bắt giữa tất cả các ngoại lệ Tại sao chúng ta không luôn luôn sử dụng câu lệnh catch không có tham số để bắt các lỗi?

Mặc dù sử dụng catch duy nhất có rất nhiều sức mạnh, nhưng nó cũng làm mất rất nhiều thông tin quan trọng về ngoại lệ được phát sinh Khi đó chúng ta sẽ không biết chính xác loại ngoại lệ xảy ra và khó có thể bảo trì cũng như khắc phục những ngoại lệ sau này

Về phía người dùng cũng vậy Nếu chương trình gặp ngoại lệ mà không có thông báo

rõ ràng cho nguời dùng thì có thể làm cho họ hoang mang, và có thể đổ lỗi cho chương trình của chúng ta không tốt ngay cả những lỗi không phải do ta Ví dụ như lỗi hết tài nguyên bộ nhớ do người dùng sử dụng quá nhiều chương trình hoạt động cùng lúc Tóm lại là chúng ta nên sử dụng catch với những tham số chi tiết để thực hiện tốt việc quản

lý các ngoại lệ được phát sinh

Có phải tất cả những ngoại lệ được đối xử một cách bình đẳng?

Không phải, có hai loại ngoại lệ, ngoại lệ hệ thống và ngoại lệ của chương trình ứng dụng Ngoại lệ của chương trình ứng dụng thì sẽ không kết thúc chương trình Còn ngoại

lệ hệ thống thì sẽ kết thúc chương trình Nói chung đó là những ngoại lệ xuất hiện trước đây Hiện nay thì người ta chia ra nhiều mức độ ngoại lệ và tùy theo từng mức độ của ngoại lệ mà chương trình của chúng ta sẽ được nhận những ứng xử khác nhau Để biết thêm chi tiết chúng ta có thể đọc thêm trong tài liệu NET Framework về xử lý ngoại lệ

Như câu trả lời bên trên tại sao tôi phải tìm hiểu nhiều về các ngoại lệ và cách thức xử

lý các ngoại lệ khi chúng được phát sinh?

Việc xây dựng một chương trình ứng dụng là hết sức phức tạp, chương trình luôn tiếm

ẩn những yếu tố không ổn định và có thể phát sinh các ngoại lệ dẫn đến những lỗi không mong muốn Việc thực hiện bắt giữ các ngoại lệ là hết sức cần thiết trong chương trình,

nó cho phép chúng ta xây dựng được chương trình hoàn thiện hơn và xử lý các thông điệp ngoại lệ tốt hơn Tìm hiểu những ngoại lệ đem đến cho chúng ta nhiều kinh nghiệm trong việc xây dựng các chương trình phức tạp hơn

Câu hỏi thêm

Hãy cho biết các từ khóa được sử dụng để xử lý ngoại lệ?

Phân biệt giữa lỗi và ngoại lệ?

Trang 17

Khi thực hiện việc bắt giữ các ngoại lệ Nếu có nhiều mức bắt giữ ngoại lệ thì chúng ta

sẽ thực hiện mức nào Từ chi tiết đến tổng quát, hay từ tổng quát đến chi tiết?

Ý nghĩa của từ khóa finally trong việc xử lý ngoại lệ?

Câu lệnh nào được dùng để phát sinh ngoại lệ?

Loại nào sau đây nên được xử lý theo ngoại lệ và loại nào thì nên được xử lý bởi các mã lệnh thông thường?

a Giá trị nhập vào của người dùng không nằm trong mức cho phép

b Tập tin không được viết mà thực hiện viết

c Đối mục truyền vào cho phương thức chứa giá trị không hợp lệ

d Đối mục truyền vào cho phương thức chứa kiểu không hợp lệ Câuhỏi 7: Nguyên nhân nào dẫn đến phát sinh ngoại lệ?

Khi nào thì ngoại lệ xuất hiện?

a Trong khi tạo mã nguồn

b Trong khi biên dịch

c Trong khi thực thi chương trình

d Khi yêu cầu đựơc đưa ta bởi người dùng cuối

Khi nào thì khối lệnh trong finally được thực hiện?

Trong namespace nào chức các lớp liên quan đến việc xử lý các ngoại lệ? Hãy cho biết một số lớp xử lý ngoại lệ quan trọng trong namespace này?

Bài tập

Hãy viết đoạn lệnh để thực hiện việc bắt giữa ngoại lệ liên quan đến câu lệnh sau đây: Ketqua = Sothu1 / Sothu2;

Chương trình sau đây có vấn đề Hãy xác định vấn đề có thể phát sinh ngoại lệ khi chạy chương trình Và viết lại chương trình hoàn chỉnh gồm các lệnh xử lý ngoại lệ:

Ngày đăng: 31/12/2015, 21:47

HÌNH ẢNH LIÊN QUAN

Bảng sau mô tả một số các lớp ngoại lệ chung được khai báo bên trong namespace System. - Những đối tượng ngoại lệ
Bảng sau mô tả một số các lớp ngoại lệ chung được khai báo bên trong namespace System (Trang 5)

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w