Giao diện IDisposable và câu lệnh using
Thuộc phần Lập trình hướng đối tượng trong hành trình C# của Coddy. Bài học 45 trên 70.
Một số đối tượng giữ các tài nguyên mà bộ thu gom rác không thể tự động dọn dẹp, như tay cầm tệp, kết nối cơ sở dữ liệu và socket mạng. Giao diện IDisposable cung cấp cách tiêu chuẩn để giải phóng các tài nguyên này khi bạn dùng xong.
Một lớp triển khai IDisposable bằng cách cung cấp phương thức Dispose():
public class FileHandler : IDisposable
{
private bool disposed = false;
public void Dispose()
{
if (!disposed)
{
Console.WriteLine("Releasing resources...");
disposed = true;
}
}
}Bạn có thể gọi Dispose() theo cách thủ công, nhưng nếu ngoại lệ xảy ra trước khi bạn đến dòng đó thì sao? Câu lệnh using đảm bảo việc dọn dẹp vẫn diễn ra ngay cả khi có sự cố:
using (FileHandler handler = new FileHandler())
{
// Làm việc với handler
} // Dispose() tự động được gọi tại đâyC# hiện đại có cú pháp gọn hơn với khai báo using, giúp giải phóng đối tượng khi đối tượng ra khỏi phạm vi:
void ProcessFile()
{
using FileHandler handler = new FileHandler();
// Làm việc với handler
} // Gọi Dispose() khi phương thức (method) kết thúcCâu lệnh using hoạt động với mọi kiểu triển khai IDisposable. Các lớp dựng sẵn như StreamReader, SqlConnection và HttpClient đều triển khai giao diện này, giúp việc quản lý tài nguyên đúng cách trở nên đơn giản và đáng tin cậy.
Thử thách
DễHãy xây dựng một chương trình mô phỏng kết nối cơ sở dữ liệu, minh họa cách quản lý tài nguyên đúng cách bằng giao diện IDisposable và câu lệnh using. Bạn sẽ tạo một lớp theo dõi thời điểm mở và đóng kết nối, đảm bảo tài nguyên luôn được giải phóng đúng cách.
Bạn sẽ sắp xếp code trong hai tệp:
DatabaseConnection.cs: Tạo lớpDatabaseConnectiontrong namespaceDataAccess, triển khaiIDisposable. Kết nối của bạn cần:- Có thuộc tính
ConnectionName(chuỗi, chỉ đọc), được thiết lập thông qua hàm khởi tạo - Theo dõi trạng thái đã giải phóng của kết nối bằng một trường boolean riêng tư
- In ra
Connection opened: {ConnectionName}khi tạo đối tượng (trong hàm khởi tạo) - Triển khai phương thức
Dispose()để in raConnection closed: {ConnectionName}, nhưng chỉ khi kết nối chưa được giải phóng (ngăn giải phóng hai lần) - Có phương thức
Query(string sql)trả vềExecuting on {ConnectionName}: {sql}
- Có thuộc tính
Program.cs: Trong tệp chính, minh họa cách quản lý tài nguyên đúng cách bằng cách sử dụng câu lệnhusingvới kết nối cơ sở dữ liệu. Tạo một kết nối, thực thi một truy vấn và để khối lệnhusingtự động xử lý việc dọn dẹp.
Bạn sẽ nhận hai đầu vào:
- Tên kết nối (ví dụ:
MainDB) - Truy vấn SQL cần thực thi (ví dụ:
SELECT * FROM Users)
Dùng câu lệnh using để tạo kết nối. Bên trong khối lệnh, gọi phương thức Query và in ra kết quả. Khi khối lệnh using kết thúc, Dispose() sẽ được gọi tự động.
Ví dụ, nếu đầu vào là MainDB và SELECT * FROM Users, đầu ra sẽ là:
Connection opened: MainDB
Executing on MainDB: SELECT * FROM Users
Connection closed: MainDBHãy chú ý rằng kết nối tự động đóng khi khối lệnh using kết thúc, bạn không cần nhớ tự gọi Dispose(). Cách làm này đảm bảo tài nguyên luôn được dọn dẹp, ngay cả khi có ngoại lệ xảy ra bên trong khối lệnh!
Tự làm thử
using System;
using DataAccess;
class Program
{
public static void Main(string[] args)
{
string connectionName = Console.ReadLine();
string sqlQuery = Console.ReadLine();
// TODO: Dùng câu lệnh 'using' để tạo một DatabaseConnection
// Trong khối lệnh using:
// 1. Gọi phương thức Query với sqlQuery
// 2. In ra kết quả của phương thức Query
// Phương thức Dispose sẽ tự động được gọi khi khối lệnh using kết thúc
}
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Các khái niệm cơ bản về lập trình hướng đối tượng
Tệp bên ngoàiKhông gian tên và chỉ thịGiới thiệu về lớp và đối tượngTừ khóa thisPhương thức và tham sốTrường và thuộc tínhHàm khởi tạoKhởi tạo đối tượngÔn tập: Máy tính đơn giản4Kế thừa
Cú pháp kế thừa cơ bản (:)Từ khóa 'base'Từ khóa virtual và overrideLớp sealedLớp cơ sở 'object'Ôn tập: hệ phân cấp nhân viên7Tính năng nâng cao
Nạp chồng toán tửBộ lập chỉ mục (this[])Ghi đè ToString()Phương thức mở rộngÔn tập: Danh sách tùy chỉnh10Các mẫu thiết kế phần 1
Giới thiệu về mẫu thiết kếSingleton an toàn với luồngMẫu FactoryMẫu Observer (sự kiện)Mẫu Strategy2Thuộc tính và thành viên tĩnh
Thuộc tính tự độngThuộc tính chỉ đọc hoặc chỉ ghiTrường và phương thức tĩnhLớp tĩnhThành viên có thân biểu thức5Đa hình và interface
Đa hình lúc biên dịch và lúc chạyInterface và lớp trừu tượngNhiều interfaceInterface tường minhUpcasting và downcastingÔn tập: bộ tính toán hình học8Các khái niệm OOP nâng cao
Ưu tiên composition hơn kế thừaGenerics (lớp và phương thức)Delegate và sự kiệnAttribute và reflectionGiao diện IDisposable và câu lệnh usingKiến thức cơ bản về dependency injection11Các mẫu thiết kế phần 2
Mẫu lệnhMẫu bộ chuyển đổiMẫu trang tríMẫu phương thức khuôn mẫuMẫu trạng tháiMẫu tổ hợpTự luyện tập: Trình biên dịch C# online