Ответ
Dispose — это ключевой метод интерфейса IDisposable, предназначенный для детерминированного освобождения неуправляемых ресурсов. В отличие от управляемой памяти, за которой следит Garbage Collector (GC), за ресурсы вроде файловых дескрипторов, сокетов или графических контекстов нужно явно "договориться" с ОС об их закрытии.
Почему это важно? Без вызова Dispose такие ресурсы могут удерживаться до сборки мусора финализатором, что приводит к утечкам, исчерпанию лимитов ОС и нестабильной работе приложения.
Стандартный паттерн использования:
public class FileLogger : IDisposable
{
private StreamWriter _writer;
private bool _disposed = false; // Флаг для защиты от повторного вызова
public FileLogger(string path)
{
_writer = new StreamWriter(path); // Захват неуправляемого ресурса (дескриптора файла)
}
public void Log(string message) => _writer.WriteLine(message);
// Публичная реализация Dispose
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); // Сообщаем GC, что финализация не нужна
}
// Защищенная виртуальная реализация
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// Освобождаем управляемые ресурсы (если они есть)
_writer?.Dispose();
}
// Здесь освобождаем неуправляемые ресурсы (если они не инкапсулированы в управляемых объектах)
_disposed = true;
}
}
// Финализатор (резервный механизм на случай, если Dispose не вызвали)
~FileLogger() => Dispose(false);
}
// ИСПОЛЬЗОВАНИЕ с блоком 'using' (рекомендуемый способ)
using (var logger = new FileLogger("log.txt"))
{
logger.Log("Application started");
} // Dispose() вызовется автоматически здесь, даже в случае исключения
Ключевые принципы:
- Идемпотентность: Последующие вызовы
Dispose()не должны вызывать ошибок. - Освобождение вложенных ресурсов: Если ваш класс владеет другими
IDisposable-объектами, вызовите ихDispose(). - Блок
using— синтаксический сахар, гарантирующий вызовDispose().