Bài 7: Xử Lý Ngoại Lệ, Các Lệnh Throw, Catch, Finally.

0
306

Này Boo. Cậu có thể mua giúp tôi một cái Hamburger chứ ???? .

Oh ! Tât nhiên là không rồi . Cậu tự mà đi mua nhé ???? – Boo đáp thản thiên.

Còn tôi thì méo mặt vì Boo ????

Tôi phản kháng ngay. Này này , chẳng phải cậu mua giúp Elly đó sao ?

Oh đó là một ngoại lệ anh bạn của tôi ơi :)).

Tôi bực bội hằng giọng :

– Hừ ! Ngoại với chả lệ ở đây . Tớ tự đi mua vậy !

Haha . Anh chàng của chúng ta bỏ đi rồi . Trong lập trình hay cuộc sống nó đều có những ngoại lệ. Đối với lập trình nói chung và C# nói riêng, tiện đây hôm nay tôi sẽ giới thiệu với các bạn bài tiếp theo của loạt bài lập trình bằng ngôn ngữ C# . Ngoại lệ là gì và cách xử lý chúng ta sao ?

[box type=”info” ]

Ngoại lệ:

Là một đối tượng đóng gói những thông tin về sự cố của một chương trình không bình thường.

[/box]

workflow7

[box type=”info” ]

*Một trình xử lý ngoại lệ: *

Là một khối lệnh chương trình được thiết kế xử lý các ngoại lệ mà chương trình phát sinh.[/box]

Xử lý ngoại lệ được thực thi trong trong câu lệnh catch. Một cách lý tưởng thì nếu một ngoại lệ được bắt và được xử lý, thì chương trình có thể sửa chữa được vấn đề và tiếp tục thực hiện hoạt động. Thậm chí nếu chương trình không tiếp tục, bằng việc bắt giữ ngoại lệ chúng ta có cơ hội để in ra những thông điệp có ý nghĩa và kết thúc chương trình một cách rõ ràng. Nếu đoạn chương trình của chúng ta thực hiện mà không quan tâm đến bất cứ ngoại lệ nào mà chúng ta có thể gặp (như khi giải phóng tài nguyên mà chương trình được cấp phát), chúng ta có thể đặt đoạn mã này trong khối finally, khi đó nó sẽ chắc chắn sẽ được thực hiện thậm chí ngay cả khi có một ngoại lệ xuất hiện.
[box type=”info” ]

Phát sinh và bắt giữ ngoại lệ

Trong ngôn ngữ C#, chúng ta chỉ có thể phát sinh (throw) những đối tượng các kiểu dữ liệu là System.Exception, hay những đối tượng được dẫn xuất từ kiểu dữ liệu này. Namespace System của CLR chứa một số các kiểu dữ liệu xử lý ngoại lệ mà chúng ta có thể sử dụng trong chương trình. Những kiểu dữ liệu ngoại lệ này bao gồm ArgumentNullException, InValidCastException, và OverflowException, cũng như nhiều lớp khác nữa.

[/box]

Như định nghĩa ở trên tôi đã nói . Chúng ta bắt gặp một số thuật ngữ như : trycatch , finally *hay throw.*

Vậy những thứ đó là gì ? . Ngay sau đây tôi sẽ cho các bạn một định nghĩa tường minh về chúng.

* Lệnh Throw*

[box type=”info” ]

Cú pháp: *throw new System.Exception(); *

Khi phát sinh ngoại lệ thì ngay tức khắc sẽ làm ngừng việc thực thi trong khi CLR sẽ tìm kiếm một trình xử lý ngoại lệ. Nếu một trình xử lý ngoại lệ không được tìm thấy trong phương thức hiện thời, thì CLR tiếp tục tìm trong phương thức gọi cho đến khi nào tìm thấy. Nếu CLR trả về lớp Main() mà không tìm thấy bất cứ trình xử lý ngoại lệ nào, thì nó sẽ kết thúc chương trình.

[/box]

* Ví dụ:*

using System; using System.Collections.Generic; using System.Text; namespace Programming_CSharp { public class Test { public static void Main() { Console.WriteLine(hàm Main….); Test t = new Test(); t.Func1(); Console.WriteLine(Kết thúc hàm Main…); } public void Func1() { Console.WriteLine(Bắt đầu hàm Func1…); Func2(); Console.WriteLine(Kết thúc hàm Func1…); } public void Func2() { Console.WriteLine(Bắt đầu hàm Func2…); throw new System.Exception(); Console.WriteLine(Kết thúc hàm Func2…); } } }

*Giải thích ví dụ trên như sau: *

Hàm Main() gọi hàm Func1(). Hàm Func1() thực hiện lệnh in ra màn hình dòng “bắt đầu hàm Func1” sau đó nó gọi tới hàm Func2(). Hàm Func2() lại in ra dòng “bắt đầu hàm Func2” sau đó nó sẽ phát sinh ra một ngoại lệ dùng câu lệnh throw new  System.Exception(). Tại đây chương trình bị ngừng thực thi, CLR sẽ tìm kiếm trình xử lý ngoại lệ cho ngoại lệ hàm Func2() phát sinh. CLR sẽ lần lượt tìm kiếm trong stack , ở hàm Func1() nhưng không có trình xử lý ngoại lệ nào, nó sẽ tiếp tục tìm đến hàm main nhưng ở hàm này cũng không có nên CLR sẽ gọi trình xử lý ngoại lệ mặc định, nó sẽ xuất ra một thông điệp lỗi như các bạn thấy khi thực thi chương trình.
[box type=”info” ]

Lệnh Try Catch Là Gì ?

Trong C#, một trình xử lý ngoại lệ hay một đoạn chương trình xử lý các ngoại lệ được gọi là một khối catch và được tạo ra với từ khóa catch. Chúng ta sẽ viết lại ví dụ trên nhưng đặt throw vào trong khối try và một khối catch sẽ dùng để xử lý ngoại lệ do lệnh throw phát sinh. Khối catch sẽ đưa ra thông báo là đã có một lỗi được xử lý

[/box]

using System; using System.Collections.Generic; using System.Text; namespace Programming_CSharp { public class Test { public static void Main() { Console.WriteLine(hàm Main….); Test t = new Test(); t.Func1(); Console.WriteLine(Kết thúc hàm Main…); Console.ReadLine(); } public void Func1() { Console.WriteLine(Bắt đầu hàm Func1…); Func2(); Console.WriteLine(Kết thúc hàm Func1…); } public void Func2() { Console.WriteLine(Bắt đầu hàm Func2…); try { Console.WriteLine(Bắt đầu Khối try); throw new System.Exception(); Console.WriteLine(Kết thúc khối try); } catch { Console.WriteLine(Ngoại lệ đã được xử lý); } Console.WriteLine(Kết thúc hàm Func2…); } } }

Tương tự như ví dụ tôi đã vừa trình bày, cho đến khi chương trình thực hiện hàm Func2() khi lệnh throw phát sinh ra ngoại lệ, chương trình sẽ bị ngừng thực hiện và CLR sẽ tìm phần xử lý ngoại lệ trong stack, đầu tiên nó sẽ gọi đến hàm Func1() tại đây hàm Func2() được gọi và nó sẽ tìm thấy phần xử lý ngoại lệ trong khối catch , nó sẽ in ra dòng “Ngoại lệ đã được xử lý”. Đó cũng là lý do mà chương trình sẽ không bao giờ in ra dòng “Kết thúc khối try”.

[box type=”info” ]

Lệnh Finally Là Gì ?

Trong một số tình huống chúng ta cần phải thực hiện bất cứ khi nào một ngoại lệ được phát sinh ra, ví dụ như việc đóng một tập tin. Để làm việc này chúng ta có thể đặt câu lệnh trong cả hai khối try và catch. Tuy nhiên có một cách giải quyết tốt hơn, đó là sử dụng câu lệnh Finnally. Các hành động đặt trong khối finnally sẽ luôn được thực hiện mà không cần quan tâm tới việc có hay không một ngoại lệ phát sinh trong chương trình.

[/box]

Chúng ta cùng xét ví dụ sau:

using System; namespace Programming_CSharp { public class Test { public static void Main() { Test t = new Test(); t.TestFunc(); Console.ReadLine(); } // chia hai số và xử lý ngoại lệ nếu có public void TestFunc() { try { Console.WriteLine(mở file); double a = 5; double b = 0; Console.WriteLine({0} /{1} = {2}, a, b, DoDivide(a,b)); Console.WriteLine(dòng này có thể xuất hiện hoặc không); } catch (System.DivideByZeroException) { Console.WriteLine(lỗi chia cho 0!); } catch { Console.WriteLine(không có ngoại lệ); } finally { Console.WriteLine(Đóng tệp.); } } // 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; } } }

Đầu tiên hãy gán* a= 5* và* b=0* chạy chương trình Bạn sẽ thấy lệnh

Console.WriteLine(dòng này có thể xuất hiện hoặc không);

Sẽ không được thực hiện do xuất hiện một ngoại lệ là lỗi chia cho 0 và chương trình sẽ tìm tới phần xử lý ngoại lệ này
mà bỏ qua phần lệnh tiếp theo.

Sau đó bạn thay đổi giá trị b=12 và chạy chương trình thì lệnh

Console.WriteLine(dòng này có thể xuất hiện hoặc không);

được thực hiện.

Tuy nhiên ở cả 2 trường hợp bạn đề thấy thực hiện lệnh

Console.WriteLine(Đóng tệp.);

Đó là vì lệnh này đã được đặt trong khối Finally.

Nắm được cách xử lý ngoại lệ qua việc sử dụng các câu lệnh throw, catch và finally sẽ giúp bạn lập trình có hiệu quả hơn. Xin chúc các bạn học tốt.

– A ! Anh bạn Andy của chúng ta về rồi này .

– Hừ ! Có chuyện gì nào ?

– Chúng ta vừa bước thêm một bước trong con đường khai sáng niềm đam mê – Boo đáp với vẻ phấn khích.

LEAVE A REPLY

Please enter your comment!
Please enter your name here