- Ngoại lệ Exception
- Bắt Ngoại lệ
- Bắt nhiều loại Ngoại lệ
- Thêm vào khối finally
- Tự phát sinh ngoại lệ
- Tạo Exeption riêng
Ngoại lệ Exception
Ngoại lệ (exception) là vấn đề - lỗi phát sinh trong quá trình thực thi chương trình. Thường khi chương trình đang chạy mà phát sinh ngoại lệ (lỗi) thì dẫn đến chương trình kết thúc ngay lập tức. Có vô số nguyên nhân để chương trình đang chạy mà phát sinh ngoại lệ, ví dụ:
- Dữ liệu người dùng nhập sai, mà chương trình không kiểm soát được
- Thực hiện các phép toán không được phép (như chia một số cho 0)
- Thao tác với tài nguyên không tồn tại (như mở file không có trên đĩa, kết nối đến CSDL không tồn tại ...)
- Thiếu bộ nhớ
- ...
Trong C# khi có một lỗi phát sinh hầu hết các lỗi đều có thể quản lý bởi thư viện C#
thì nó sẽ phát sinh ra một đối
tượng lớp Exeption
(System.System) hoặc đối tượng lớp nào đó kế thừa từ Exception
Khi một đối tượng lớp Exception
sinh ra - mà chương trình không chủ động xử lý đối tượng này thì
chương trình sẽ kết thúc. Đối tượng lớp Exception
chứa trong nó các thông tin về lỗi (dòng thông báo, nguyên nhân lỗi,
nơi phát sinh lỗi ...)
Thử phát sinh một Exception
Chạy đoạn code sau:
static void Main(string[] args) { int[] mynumbers = new int[] {1,2,3}; int i = mynumbers[10]; // chỗ này phát sinh lỗi }
Đoạn code trên khi chạy sẽ phát sinh lỗi bởi vì, mynumbers
là mảng có 3 phần tử, nhưng chi đọc
lại cố tình truy cập đến phần tử thứ 11 mynumber[10]
Do lỗi này không được xử lý, nên chương trình kết thúc ngay lập tức và có đọc được thông báo về lỗi như hình trên.
Xử lý ngoại lệ - Exception
Nếu ngoại lệ (lỗi thực thi) phát sinh mà không xử lý thì chương trình sẽ dừng đột ngột
- nếu muốn xử lý ngoại lệ thì ta cần bắt lấy nó và điều hướng chương trình một cách thích hợp.
Để bắt ngoại lệ ta sử dụng câu lệnh
try ... catch ... như sau:
try { // Các khối code được giám sát để bắt lỗi nếu có // nếu có lỗi sẽ phát sinh ngoại lệ Exception // Ngoại lệ này bắt lại được ở khối catch } catch (Exception loi) { // Khối này thực thi khi có lỗi - đối tượng Exception bắt được lưu ở biến loi }
Như vậy đoạn code nào muốn giám sát để bắt ngoại lệ - thì đưa vào khối try
, nếu ngoại lệ xảy ra
do code trong khối đó thì sẽ bắt được - chương trình sẽ không kết thúc mà lập tức chuyển sang khối catch
,
tại đó bạn có ngay đối tượng lớp Exception - bạn cần xử lý theo logic ứng dụng của bạn điều hướng chương trình một
cách thích hợp ở đây.
Đối tượng lớp Exception có một số thuộc tính, tiện dụng cho bạn gỡ rối đó là:
Message
chuỗi chứa nội dung thông báo lỗiStackTrace
chuỗi chứa các bước thực thi chương trình cho đến khi bị lỗi (có chứa các phương thức, hàm khi thực thi gây lỗi, vị trí file lỗi ...)Source
chứa tên ứng dụng hoặc đối tượng bị lỗi
Thực hành bắt lỗi:
static void Main(string[] args) { try { // khối này được giám sát để bắt lỗi - khi nó phát sinh int[] mynumbers = new int[] {1,2,3}; int i = mynumbers[10]; // dòng này phát sinh lỗi Console.WriteLine(i); // dòng này không được thực thi vì lỗi trên } catch (Exception loi) { // khối này thực thi khi bắt được lỗi Console.WriteLine("Có lỗi rồi"); Console.WriteLine(loi.Message); } }
Có lỗi rồi Index was outside the bounds of the array.
Bắt nhiều ngoại lệ
Trong .NET từ lớp cơ sở Exception
nó xây dựng nên rất nhiều loại ngoại lệ khác phục vụ
chi tiết cho từng loại lỗi phát sinh khác nhau như:
FileNotFoundException
, FormatException
,
OutOfMemoryException
, ArgumentException
,
NullReferenceException
,
IndexOutOfRangeException
,
DivideByZeroException
...
Để bắt cụ thể một loại ngoại lệ nào đó chỉ việc thêm một khối catch
tương ứng với ngoại lệ đó.
try { int x = 10; int y = 0; int z = x / y; } catch (DivideByZeroException e1) { Console.WriteLine(e1.Message); } catch (Exception e2) { Console.WriteLine(e2.Message); }
Khi có ngoại lệ chia một số cho 0, thì khối catch
với ngoại lệ kiểu DivideByZeroException
được thi hành, còn ngoại lệ khác sẽ do khối catch
thứ 2 thi hành. Bằng cách như vậy bạn có thể
khai báo nhiều khối catch tùy nhu cầu.
Thêm vào khối finally
Trong lệnh try ... catch, bạn có thể thêm một tùy chọn là khối finally
, code trong khối này được
thực thi ngay cả khi có phát sinh ngoại lệ hay không. Khối này cơ bản để giải phóng các tài nguyên chiếm giữ.
int x = 10; int y = 0; int z = 0; try { z = x / y; } catch (DivideByZeroException e1) { Console.WriteLine(e1.Message); } finally { // Luôn được thi hành dù có phát sinh ngoại lệ hay không Console.WriteLine(z); }
Phát sinh ngoại lệ với throw
Nếu code của bạn muốn phát sinh ngoại lệ cho biết có một lỗi nào đó vừa xảy ra thì bạn cần tạo ra một đối tượng lớp
Exception
hoặc đối tượng thuộc lớp nào đó kế thừa từ Exception
,
sau đó phát sinh bằng lệnh throw
Ví dụ, xây dựng hàm Thuong nếu tham số thứ 2 bằng không thì phát sinh ngoại lệ.
public static double Thuong(double x, double y) { if (y == 0) { // Khởi tạo ngoại lệ, tham số là thông báo lỗi Exception myexception = new Exception("Số chia không được bằng 0"); // phát sinh ngoại lệ, code phía sau throw không được thực thi throw myexception; } return x / y; } static void Main(string[] args) { double z = Thuong(100,0); }
Khi chạy, ngoại lệ sẽ phát sinh, và ngoại lệ đó là myexception
, chứa thông báo lỗi do bạn thiết lập.
Do chương trình không bắt ngoại lệ này, nên nó dừng ngay lập tức
Giờ muốn bắt chính ngoại lệ do bạn phát sinh
static void Main(string[] args) try { double z = Thuong(100,0); } catch (Exception e) { Console.WriteLine(e.Message); } }
Chạy, sẽ in ra dòng: "Số chia không được bằng 0"
Tạo Exeption riêng
Nếu muốn tạo ra các lớp để quẳng ra các lỗi khi cần thiết, thì chỉ việc kế thừa lớp Exception
.
Lợi ích việc tạo ra lớp riêng, nó giúp cho việc quản lý lỗi - gỡ rối tốt hơn.
Ví dụ, người dùng đưa vào một dữ liệu chuỗi string
, chuỗi này phải có độ dài dưới 10 ký tự,
nếu dài hơn thì phát sinh Exception riêng, bạn sẽ xây dựng một lớp kế thừa từ Exception chuyên dành cho lỗi này
Tạo thử một lớp đặt tên là DataTooLongExeption
như sau:
using System; namespace CS015_Error_Exception { public class DataTooLongExeption : Exception { const string erroMessage = "Dữ liệu quá dài"; public DataTooLongExeption() : base(erroMessage) { } } }
Sử dụng nó để phát sinh ngoại lệ
using System; namespace CS15_Error { class Program { public static void UserInput(string s) { if (s.Length > 10) { Exception e = new DataTooLongExeption(); throw e; // lỗi văng ra } //Other code - no exeption } static void Main(string[] args)a { try { UserInput("Đây là một chuỗi rất dài ..."); } catch (DataTooLongExeption e) { Console.WriteLine(e.Message); } catch (Exception otherExeption) { Console.WriteLine(otherExeption.Message); } } } }
Khi chạy, ngoại lệ phát sinh và bắt lại được - nó in ra thông báo của ngoại lệ - dữ liệu quá dài
Mã nguồn hoặc tải về tại ex015