Ответ
IDisposable — это интерфейс, который предоставляет механизм для детерминированного освобождения неуправляемых ресурсов (файловые дескрипторы, сетевое соединение, дескрипторы окон, подключения к БД), которые не контролируются сборщиком мусора (GC).
Почему это важно: Сборщик мусора C# управляет только памятью, выделенной в управляемой куче. Ресурсы вроде файлов или сокетов существуют вне этой кучи, и если их не освобождать явно, это приведёт к утечкам ресурсов.
Базовая реализация паттерна Disposable:
public class DatabaseConnection : IDisposable
{
private SqlConnection _connection; // Пример неуправляемого ресурса
private bool _disposed = false; // Флаг для защиты от повторного вызова
public DatabaseConnection(string connectionString)
{
_connection = new SqlConnection(connectionString);
_connection.Open();
}
// Публичный метод, который должен вызывать клиентский код
public void Dispose()
{
Dispose(true); // Освобождаем управляемые и неуправляемые ресурсы
GC.SuppressFinalize(this); // Отменяем вызов финализатора, т.к. очистка уже выполнена
}
// Защищённый виртуальный метод, где происходит реальная очистка
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing)
{
// Освобождаем управляемые ресурсы (те, у которых тоже есть Dispose)
_connection?.Close();
_connection?.Dispose();
}
// Здесь освобождаем неуправляемые ресурсы (например, через P/Invoke)
// В данном примере SqlConnection — управляемая обёртка, поэтому тут может быть пусто.
_disposed = true;
}
// Финализатор (деструктор) — резервный механизм на случай, если Dispose не был вызван.
~DatabaseConnection()
{
Dispose(false); // Вызываем только для очистки неуправляемых ресурсов
}
}
Использование:
Лучший способ работы с IDisposable — конструкция using, которая гарантирует вызов Dispose() даже при возникновении исключения.
// using гарантирует вызов connection.Dispose() при выходе из блока
using (var connection = new DatabaseConnection("Server=myServer;Database=myDB;"))
{
// Работа с подключением
// При любом исходе (нормальном завершении или исключении) Dispose() будет вызван.
}
// Здесь ресурс connection уже освобождён.
Ключевой момент: IDisposable — это не про управление памятью, а про управление жизненным циклом внешних ресурсов. Все классы .NET, работающие с файлами (FileStream), сетью (HttpClient), графикой (Bitmap), реализуют этот интерфейс.