Hướng dẫn xử lý ngoại lệ trong C#
1. Exception là gì?
Trong ví dụ này có một đoạn code lỗi nguyên nhân do phép chia cho 0. Việc chia cho 0 gây ra ngoại lệ: DivideByZeroException
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExceptionTutorial
{
class HelloException
{
public static void Main(string[] args)
{
Console.WriteLine("Three");
// Phép chia này hoàn toàn không có vấn đề.
int value = 10 / 2;
Console.WriteLine("Two");
// Phép chia này cũng vậy
value = 10 / 1;
Console.WriteLine("One");
int d = 0;
// Phép chia này có vấn đề, chia cho 0.
// Lỗi đã xẩy ra tại đây.
value = 10 / d;
// Và dòng code dưới đây sẽ không được thực thi.
Console.WriteLine("Let's go!");
Console.Read();
}
}
}
Bạn có thể thấy thông báo lỗi trên màn hình Console, thông báo lỗi rất rõ ràng, xẩy ra ở dòng thứ mấy trên code.
Three
Two
One
- Chương trình đã chạy hoàn toàn bình thường từ các bước (1),(2) cho tới (5)
- Bước thứ (6) xẩy ra vấn đề khi chia cho 0.
- Chương trình đã nhẩy ra khỏi hàm main, và dòng code thứ (7) đã không được thực hiện.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExceptionTutorial
{
class HelloCatchException
{
public static void Main(string[] args)
{
Console.WriteLine("Three");
// Phép chia này không có vấn đề.
int value = 10 / 2;
Console.WriteLine("Two");
// Phép chia này không có vấn đề.
value = 10 / 1;
Console.WriteLine("One");
int d = 0;
try
{
// Phép chia này có vấn đề, chia cho 0.
// Lỗi đã xẩy ra tại đây.
value = 10 / d;
// Dòng code này sẽ không được chạy.
Console.WriteLine("Value =" + value);
}
catch (DivideByZeroException e)
{
// Các đoạn code trong catch được thực thi
Console.WriteLine("Error: " + e.Message);
Console.WriteLine("Ignore...");
}
// Dòng code này được thực thi.
Console.WriteLine("Let's go!");
Console.Read();
}
}
}
Three
Two
One
Error: Attempted to divide by zero.
Ignore...
Let't go!
- Các bước (1)-(6) hoàn toàn bình thường.
- Ngoại lệ xẩy ra tại bước (7), vấn đề chia cho 0.
- Lập tức nó nhẩy vào thực thi lệnh trong khối catch, bước (8) bị bỏ qua.
- Bước (9), (10) được thực hiện.
- Bước (11), (12) được thực hiện.
2. Phân cấp các ngoại lệ
- Class ở mức cao nhất là Exception
- Hai class con trực tiếp là SystemException và AplicationException.
Kiểu ngoại lệ | Mô tả |
Exception | Lớp cơ bản của mọi ngoại lệ. |
SystemException | Lớp cơ bản của mọi ngoại lệ phát ra tại thời điểm chạy của chương trình. |
IndexOutOfRangeException | Được ném ra tại thời điểm chạy khi truy cập vào một phần tử của mảng với chỉ số không đúng. |
NullReferenceException | Ném ra tại thời điểm chạy khi một đối tượng null được tham chiếu. |
AccessViolationException | Ném ra tại thời điểm chạy khi tham chiếu vào vùng bộ nhớ không hợp lệ. |
InvalidOperationException | Ném ra bởi phương thức khi ở trạng thái không hợp lệ. |
ArgumentException | Lớp cơ bản cho các ngoại lệ liên quan tới đối số (Argument). |
ArgumentNullException | Lớp này là con của ArgumentException, nó được ném ra bởi phương thức mà không cho phép thông số null truyền vào. |
ArgumentOutOfRangeException | Lớp này là con của ArgumentException, nó được ném ra bởi phương thức khi một đối số không thuộc phạm vi cho phép truyền vào nó. |
ExternalException | Lớp cơ bản cho các ngoại lệ xẩy ra hoặc đến từ môi trường bên ngoài. |
COMException | Lớp này mở rộng từ ExternalException, ngoại lệ đóng gói thông tin COM. |
SEHException | Lớp này mở rộng từ ExternalException, nó tóm lược các ngoại lệ từ Win32. |
3. Bắt ngoại lệ thông qua try-catch
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExceptionTutorial
{
class AgeException : ApplicationException
{
public AgeException(String message)
: base(message)
{
}
}
class TooYoungException : AgeException
{
public TooYoungException(String message)
: base(message)
{
}
}
class TooOldException : AgeException
{
public TooOldException(String message)
: base(message)
{
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExceptionTutorial
{
class AgeUtils
{
// Phương thức này làm nhiệm vụ kiểm tra tuổi.
// Nếu tuổi nhỏ hơn 18 method sẽ ném ra ngoại lệ TooYoungException
// Nếu tuổi lớn hơn 40 method sẽ ném ra ngoại lệ TooOldException
public static void checkAge(int age)
{
if (age < 18)
{
// Nếu tuổi nhỏ hơn 18, ngoại lệ sẽ được ném ra
// Method này kết thúc tại đây.
throw new TooYoungException("Age " + age + " too young");
}
else if (age > 40)
{
// Nếu tuổi lớn hơn 40, ngoại lệ sẽ được ném ra.
// Method này kết thúc tại đây.
throw new TooOldException("Age " + age + " too old");
}
// Nếu tuổi nằm trong khoảng 18-40.
// Đoạn code này sẽ được chạy.
Console.WriteLine("Age " + age + " OK!");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExceptionTutorial
{
class TryCatchDemo1
{
public static void Main(string[] args)
{
// Bắt đầu tuyển dụng ...
Console.WriteLine("Start Recruiting ...");
// Kiểm tra tuổi của bạn.
Console.WriteLine("Check your Age");
int age = 50;
try
{
AgeUtils.checkAge(age);
Console.WriteLine("You pass!");
}
catch (TooYoungException e)
{
// Thông báo về ngoại lệ "quá trẻ" ..
Console.WriteLine("You are too young, not pass!");
Console.WriteLine(e.Message);
}
catch (TooOldException e)
{
// Thông báo về ngoại lệ "quá nhiều tuổi" ..
Console.WriteLine("You are too old, not pass!");
Console.WriteLine(e.Message);
}
Console.Read();
}
}
}
Start Recruiting ...
Check your Age
You are too old, not pass!
Age 50 too old
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExceptionTutorial
{
class TryCatchDemo2
{
public static void Main(string[] args)
{
// Bắt đầu tuyển dụng ...
Console.WriteLine("Start Recruiting ...");
// Kiểm tra tuổi của bạn.
Console.WriteLine("Check your Age");
int age = 15;
try
{
// Chỗ này có thể ném ra (throw) ngoại lệ TooOldException,
// hoặc TooYoungException
AgeUtils.checkAge(age);
Console.WriteLine("You pass!");
}
// Nếu có ngoại lệ xẩy ra, kiểu AgeException
// Khối catch này sẽ được chạy.
catch (AgeException e)
{
Console.WriteLine("Your age invalid, you not pass");
Console.WriteLine(e.Message);
}
Console.Read();
}
}
}
Start Recruiting ...
Check your Age
Your age invalid, you not pass
Age 15 too young
4. Khối try-catch-finally
try {
// Làm gì đó tại đây
} catch (Exception1 e) {
// Làm gì đó tại đây
} catch (Exception2 e) {
// Làm gì đó tại đây
} finally {
// Khối finally luôn luôn được thực thi
// Làm gì đó tại đây.
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExceptionTutorial
{
class TryCatchFinallyDemo
{
public static void Main(string[] args)
{
String text = "001234A2";
int value = toInteger(text);
Console.WriteLine("Value= " + value);
Console.Read();
}
public static int toInteger(String text)
{
try
{
Console.WriteLine("Begin parse text: " + text);
// Tại đây có thể phát sinh ngoại lệ FormatException
int value = int.Parse(text);
return value;
}
catch (FormatException e)
{
// Trong trường hợp 'text' không phải là số.
// Khối catch này sẽ được thực thi.
Console.WriteLine("Number format exception: " + e.Message);
return 0;
}
finally
{
Console.WriteLine("End parse text: " + text);
}
}
}
}
Begin parse text: 001234A2
Number format exception: Input string was not in a correct format.
End parse text: 001234A2
Value= 0
5. Gói một Exception trong một Exception khác
- Person: Mô phỏng một người tham gia tuyển dụng vào công ty với các thông tin
- Tên, tuổi, giới tính.
- GenderException: Ngoại lệ giới tính.
- ValidateException: Ngoại lệ đánh giá thí sinh.
- ValidateUtils: Class có method tĩnh đánh giá thí sinh đủ tiêu chuẩn không.
- Tiêu chuẩn là những người độ tuổi 18-40
- Và là Nam.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExceptionTutorial
{
class Person
{
public static readonly string MALE = "male";
public static readonly string FEMALE = "female";
private string name;
private string gender;
private int age;
public Person(string name, string gender, int age)
{
this.name = name;
this.gender = gender;
this.age = age;
}
public string GetName()
{
return name;
}
public string GetGender()
{
return gender;
}
public int GetAge()
{
return age;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExceptionTutorial
{
class GenderException : ApplicationException
{
public GenderException(String message)
: base(message)
{
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExceptionTutorial
{
class ValidateException : ApplicationException
{
// Gói (wrap) một Exception trong một Exception.
public ValidateException(Exception e) : base("Something invalid", e)
{
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExceptionTutorial
{
class ValidateUtils
{
// Phương thức kiểm tra một người tham gia tuyển dụng.
public static void CheckPerson(Person person)
{
try
{
// Kiểm tra tuổi.
// Hợp lệ là trong khoảng 18-40
// Method này có thể ném ra TooOldException,TooYoungException.
AgeUtils.checkAge(person.GetAge());
}
catch (Exception e)
{
// Nếu không hợp lệ
// Gói ngoại lệ này bởi ValidateException, và throw.
throw new ValidateException(e);
}
// Nếu người đó là Nữ, nghĩa là không hợp lệ.
if (person.GetGender() == Person.FEMALE)
{
GenderException e = new GenderException("Do not accept women");
throw new ValidateException(e);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExceptionTutorial
{
class WrapperExceptionDemo
{
public static void Main(string[] args)
{
// Một ứng viên tham gia tuyển dụng.
Person person = new Person("Marry", Person.FEMALE, 20);
try
{
// Ngoại lệ có thể xẩy ra tại đây.
ValidateUtils.CheckPerson(person);
}
catch (ValidateException wrap)
{
// Lấy ra nguyên nhân thực sự.
// Mà có thể là TooYoungException, TooOldException, GenderException.
Exception cause = wrap.GetBaseException();
if (cause != null)
{
Console.WriteLine("Message: " + wrap.Message);
Console.WriteLine("Base Exception Message: " + cause.Message);
}
else
{
Console.WriteLine("Message: " + wrap.Message);
}
}
Console.Read();
}
}
}
Age 20 OK!
Message: Something invalid
Base Exception Message: Do not accept women
6. Một số ngoại lệ thông dụng
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExceptionTutorial
{
class NullReferenceExceptionDemo
{
// Ví dụ đây là một phương thức có thể trả về chuỗi null.
public static string GetString()
{
if (1 == 2)
{
return "1==2 !!";
}
return null;
}
public static void Main(string[] args)
{
// Đây là một đối tượng có tham chiếu khác null.
string text1 = "Hello exception";
// Lấy độ dài của chuỗi.
int length = text1.Length;
Console.WriteLine("Length text1 = " + length);
// Đây là một đối tượng có tham chiếu (reference) null.
String text2 = GetString(); // text2 = null.
// Lấy độ dài của chuỗi.
// NullReferenceException sẽ xẩy ra tại đây.
length = text2.Length; // ==> Runtime Error!
Console.WriteLine("Finish!");
Console.Read();
}
}
}
Bạn có thể sửa code trên giống dưới đây, để tránh NullReferenceException:
// Đây là một đối tượng có tham chiếu null.
String text2 = GetString(); // ==> return null
// Kiểm tra để đảm bảo rằng 'text2' là khác null,
// Thay vì sử dụng try-catch.
if (text2 != null)
{
length = text2.Length;
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ExceptionTutorial
{
class IndexOutOfRangeExceptionDemo
{
public static void Main(string[] args)
{
String[] strs = new String[] { "One", "Two", "Three" };
// Truy cập vào phần tử tại chỉ số 0.
String str1 = strs[0];
Console.WriteLine("String at 0 = " + str1);
// Truy cập vào phần tử có chỉ số 5
// IndexOutOfRangeException xẩy ra tại đây.
String str2 = strs[5];
Console.WriteLine("String at 5 = " + str2);
Console.Read();
}
}
}
if (strs.length > 5)
{
String str2 = strs[5];
Console.WriteLine("String at 5 = " + str2);
}
else
{
Console.WriteLine("No elements with index 5");
}
Các hướng dẫn lập trình C#
- Thừa kế và đa hình trong C#
- Bắt đầu với C# cần những gì?
- Học nhanh C# cho người mới bắt đầu
- Cài đặt Visual Studio 2013 trên Windows
- Abstract class và Interface trong C#
- Cài đặt Visual Studio 2015 trên Windows
- Nén và giải nén trong C#
- Hướng dẫn lập trình đa luồng trong C#
- Hướng dẫn và ví dụ C# Delegate và Event
- Cài đặt AnkhSVN trên Windows
- Lập trình C# theo nhóm sử dụng Visual Studio và SVN
- Cài đặt .Net Framework
- Access Modifier trong C#
- Hướng dẫn và ví dụ C# String và StringBuilder
- Hướng dẫn và ví dụ C# Property
- Hướng dẫn và ví dụ C# Enum
- Hướng dẫn và ví dụ C# Structure
- Hướng dẫn và ví dụ C# Generics
- Hướng dẫn xử lý ngoại lệ trong C#
- Hướng dẫn và ví dụ Date Time trong C#
- Thao tác với tập tin và thư mục trong C#
- Hướng dẫn sử dụng Stream - luồng vào ra nhị phân trong C#
- Hướng dẫn sử dụng biểu thức chính quy trong C#
- Kết nối cơ sở dữ liệu SQL Server trong C#
- Làm việc với cơ sở dữ liệu SQL Server trong C#
- Kết nối cơ sở dữ liệu MySQL trong C#
- Làm việc với cơ sở dữ liệu MySQL trong C#
- Kết nối cơ sở dữ liệu Oracle trong C# không cần Oracle Client
- Làm việc với cơ sở dữ liệu Oracle trong C#