Khái niệm
Ngoại lệ (Exception) là lỗi xảy ra tại runtime, làm gián đoạn luồng thực thi bình thường. C# xử lý ngoại lệ bằng 4 từ khóa: try, catch, finally, throw.
Cơ chế 4 từ khóa
| Từ khóa | Chức năng |
|---|---|
try | Khối mã có thể ném ngoại lệ. Bắt buộc theo sau bởi catch hoặc finally. |
catch | Bắt và xử lý ngoại lệ cụ thể. Có thể có nhiều catch cho các loại exception khác nhau. |
finally | Khối mã **luôn chạy** sau try/catch (dù có exception, return, hay không). Dùng cho cleanup. |
throw | Ném ngoại lệ (tạo mới hoặc ném lại exception hiện tại). |
Hệ thống phân cấp Exception
System.Exception- cơ sở tất cả ngoại lệ.System.SystemException- ngoại lệ hệ thống (NullReference, DivideByZero, IndexOutOfRange...).System.ApplicationException- base cho ngoại lệ ứng dụng ( ít dùng hiện nay, khuyến nghị kế thừa trực tiếp từ Exception).
Ví dụ 1: Try-catch-finally cơ bản
using System;
public class Demo
{
int result = 0;
public void Division(int num1, int num2)
{
try
{
result = num1 / num2;
}
catch (DivideByZeroException e)
{
Console.WriteLine($"Exception caught: {e.Message}");
}
finally
{
Console.WriteLine($"Result = {result}"); // Luôn chạy
}
}
public static void Main(string[] args)
{
Demo d = new Demo();
d.Division(100, 0);
}
}
Kết quả
Exception caught: Attempted to divide by zero.
Result = 0
Ví dụ 2: Reflection với try-catch
using System;
using System.Reflection;
public class Demo
{
public static void Main()
{
Type type = typeof(Subject);
try
{
FieldInfo fieldInfo = type.GetField("SubName");
MemberInfo[] info = type.GetMember("SubName");
Console.Write("Members = ");
for (int i = 0; i < info.Length; i++)
Console.WriteLine($" {info[i]}");
Console.WriteLine($"FieldInfo = {fieldInfo}");
}
catch (ArgumentNullException e)
{
Console.WriteLine($"Exception: {e.GetType().Name} - {e.Message}");
}
}
}
public class Subject
{
public string SubName = "Science";
}
Kết quả
Members = System.String SubName
FieldInfo = System.String SubName
Best Practices
- Chỉ catch ngoại lệ bạn **có thể xử lý** được. Đừng catch
Exceptionchung chung trừ khi log và re-throw. - Dùng
throw;(không tham số) để ném lại exception gốc, bảo toàn stack trace. - Sử dụng
using/IDisposablethay vì try/finally thủ công cho tài nguyên. - Tạo custom exception kế thừa từ
Exception(không phải ApplicationException). - Tránh dùng exception cho control flow bình thường (performance).
Exception Filters (C# 6+)
try { ... }
catch (SqlException ex) when (ex.Number == 1205) // Deadlock
{
// Retry logic
}
catch (SqlException ex) when (ex.Number == 2627) // Unique constraint
{
// Handle duplicate
}