Xử lý ngoại lệ (Try/Catch/Finally) trong C#

Exception (ngoại lệ) là một vấn đề xuất hiện trong khi thực thi chương trình. Một Exception trong C# là phản hồi về một tình huống ngoại lệ mà xuất hiện trong khi chương trình đang chạy, ví dụ như chia cho số 0.

Exception cung cấp một cách để truyền điều khiển từ một phần của một chương trình tới phần khác. Cũng giống như việc xử lý ngoại lệ trong PHP, Exception Handling (Xử lý ngoại lệ) trong C# được xây dựng dựa trên 4 từ khóa là: try, catch, finally,  throw.

  • try: Một khối try nhận diện một khối code mà ở đó các exception cụ thể được kích hoạt. Nó được theo sau bởi một hoặc nhiều khối catch.
  • catch: Một chương trình bắt một Exception với một Exception Handler tại vị trí trong một chương trình nơi bạn muốn xử lý vấn đề đó. Từ khóa catch trong C# chỉ dẫn việc bắt một exception.
  • finally: Một khối finally được sử dụng để thực thi một tập hợp lệnh đã cho, dù có hay không một exception đươc ném hoặc không được ném. Ví dụ, nếu bạn mở một file, nó phải được đóng, nếu không sẽ có một exception được tạo ra.
  • throw: Một chương trình ném một exception khi có một vấn đề xuất hiện. Điều này được thực hiện bởi sử dụng từ khóa throw trong C#.

Cú pháp

Giả sử một khối tạo một Exeption, một phương thức bắt một exception bởi sử dụng kết hợp các từ khóa try và catch. Một khối try/catch được đặt xung quanh code mà có thể tạo một exception. Code bên trong một khối try/catch được xem như là code được bảo vệ, và cú pháp để sử dụng try/catch trong C# như sau:

try {
 // các lệnh có thể gây ra ngoại lệ (exception)
} catch( tên_ngoi_l e1 ) {
 // phần code để xử lý lỗi
} catch( tên_ngoi_l e2 ) {
 // phần code để xử lý lỗi
} catch( tên_ngoi_l eN ) {
 // phần code để xử lý lỗi
} finally {
 // các lệnh được thực thi
}

Bạn có thể liệt kê nhiều lệnh catch để bắt các kiểu exception khác nhau trong trường hợp khối try của bạn xuất hiện nhiều hơn một exception trong các tình huống khác nhau.

Lớp Exception trong C#

Các Exception trong C# được biểu diễn bởi các lớp. Các lớp Exception trong C# chủ yếu được kế thừa một cách trực tiếp hoặc không trực tiếp từ lớp System.Exception trong C#. Một số lớp Exception kế thừa từ lớp System.Exception là các lớp System.ApplicationException và System.SystemException.

Lớp System.ApplicationException hỗ trợ các exception được tạo bởi các chương trình ứng dụng. Vì thế, các exception được định nghĩa bởi lập trình viên nên kế thừa từ lớp này.

Lớp System.SystemException là lớp cơ sở cho tất cả system exception tiền định nghĩa.

Bảng sau cung cấp một số lớp Exception tiền định nghĩa được kế thừa từ lớp Sytem.SystemException trong C#:

Lớp Exception Mô tả
System.IO.IOException Xử lý các I/O error.
System.IndexOutOfRangeException Xử lý các lỗi được tạo khi một phương thức tham chiếu tới một chỉ mục bên ngoài dãy mảng.
System.ArrayTypeMismatchException Xử lý các lỗi được tạo khi kiểu là không phù hợp với kiểu mảng.
System.NullReferenceException Xử lý các lỗi được tạo từ việc tham chiếu một đối tượng null.
System.DivideByZeroException Xử lý các lỗi được tạo khi chia cho số 0.
System.InvalidCastException Xử lý lỗi được tạo trong khi ép kiểu.
System.OutOfMemoryException Xử lý lỗi được tạo từ việc thiếu bộ nhớ rỗi.
System.StackOverflowException Xử lý lỗi được tạo từ việc tràn ngăn xếp (stack).

Xử lý ngoại lệ (Exception Handling) trong C#

C# cung cấp một giải pháp mang tính cấu trúc cao để xử lý ngoại lệ trong form của các khối try và catch. Sử dụng các khối này, các lệnh chính của chương trình được tách biệt khỏi các lệnh xử lý lỗi trong C#.

Những khối xử lý ngoại lệ này được triển khai bằng cách dùng các từ khóa try, catch và finally trong C#. Ví dụ sau throw một exception khi chia cho số 0.

using System;

namespace VdXuLyNgoaiLe {
   class PhepChia {
      int result;
      
      PhepChia() {
         result = 0;
      }
      public void chia(int so1, int so2) {
         try {
            result = so1 / so2;
         } catch (DivideByZeroException e) {
            Console.WriteLine("Exception caught: {0}", e);
         } finally {
            Console.WriteLine("Kết quả: {0}", result);
         }
      }
      static void Main(string[] args) {
         PhepChia d = new PhepChia();
         d.chia(25, 0);
         Console.ReadKey();
      }
   }
}

Khi biên dịch và chạy chương trình C# trên sẽ cho kết quả sau:

Exception caught: System.DivideByZeroException: Attempted to divide by zero.
 at VdXuLyNgoaiLe.PhepChia.chia (System.Int32 so1, System.Int32 so2) [0x00000] in <c62f1be2fa6b4da1ab04bbf46301cef3>:0 
Kết quả: 0

Tạo User-Defined Exception trong C#

Bạn cũng có thể tự định nghĩa các exception. Các lớp User-Defined Exception được kế thừa từ lớp ApplicationException trong C#. Ví dụ sau minh họa cho điều này:

Tạo 3 lớp có tên lần lượt là như sau:

Lớp Temperature

using System;

namespace VdDinhNghiaException {
   class KtraNhietDo {
      static void Main(string[] args) {
         NhietDo nhiet = new NhietDo();
         try {
            nhiet.xemNhietDo();
         } catch(TempIsZeroException e) {
            Console.WriteLine("TempIsZeroException: {0}", e.Message);
         }
         Console.ReadKey();
      }
   }
}
public class TempIsZeroException: Exception {
   public TempIsZeroException(string message): base(message) {
   }
}
public class NhietDo {
   int temperature = 0;
   
   public void xemNhietDo() {
      
      if(temperature == 0) {
         throw (new TempIsZeroException("Mức nhiệt độ bằng 0!"));
      } else {
         Console.WriteLine("Nhiệt độ: {0}", temperature);
      }
   }
}

Biên dịch và chạy chương trình C# trên sẽ cho kết quả sau:

TempIsZeroException: Mc nhit độ bng 0!

Ném (throw) các Object trong C#

Bạn có thể ném một đối tượng nếu nó: hoặc trực tiếp hoặc gián tiếp được kế thừa từ lớp System.Exception trong C#. Bạn có thể sử dụng một lệnh throw trong khối catch để ném đối tượng hiện diện đó:

Catch(Exception e)
{
 ...
 Throw e
}