Tìm hiểu và sử dụng ngoại lệ Exception câu lệnh try catch trong C# C Sharp

Cách bắt những lỗi ngoại lệ Exception phát sinh trong lập trình C # với cấu lệnh try catch finally, cách tạo và phát sinh những ngoại lệ

Ngoại lệ Exception

Ngoại lệ ( exception ) là yếu tố – lỗi phát sinh trong quy 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 do để 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]

CS
Do lỗi này không được giải quyết và xử lý, nên chương trình kết thúc ngay lập tức và có đọc được thông tin 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ố ít thuộc tính, tiện lợi cho bạn tháo gỡ đó là :

  • Message chuỗi chứa nội dung thông báo lỗi
  • StackTrace 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ụ, kiến thiết 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

CS
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