← Назад к вопросам

Для чего используется паттерн IDisposable?

2.0 Middle🔥 201 комментариев
#ASP.NET и Web API

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

IDisposable паттерн

IDisposable — это интерфейс для явного освобождения неуправляемых ресурсов (файлы, БД, сокеты).

Проблема

public class FileProcessor
{
    private StreamReader _reader;
    public FileProcessor(string path) => _reader = new StreamReader(path);
    public string ReadLine() => _reader.ReadLine();
}

var proc = new FileProcessor("data.txt");
var line = proc.ReadLine();
// Файл остается открытым!

Решение с IDisposable

public class FileProcessor : IDisposable
{
    private StreamReader _reader;
    private bool _disposed = false;

    public FileProcessor(string path) => _reader = new StreamReader(path);

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (_disposed) return;
        if (disposing)
            _reader?.Dispose();
        _disposed = true;
    }

    ~FileProcessor() => Dispose(false);
}

Использование

using (var proc = new FileProcessor("data.txt"))
{
    var line = proc.ReadLine();
} // Dispose() вызовется автоматически

// Или C# 8+
using var proc = new FileProcessor("data.txt");
var line = proc.ReadLine();
// Dispose() при выходе из области видимости

Когда использовать

  • Файлы и потоки (FileStream, StreamWriter)
  • Подключения к БД (SqlConnection, DbContext)
  • Сетевые соединения (TcpClient)
  • Неуправляемые ресурсы (IntPtr)
  • Таймеры (Timer)

Реальные примеры

// FileStream
using var stream = new FileStream("file.txt", FileMode.Open);
var content = await stream.ReadAsync(buffer, 0, buffer.Length);

// SqlConnection
using var conn = new SqlConnection(connectionString);
await conn.OpenAsync();

// DbContext
using var context = new AppDbContext();
var users = await context.Users.ToListAsync();

IAsyncDisposable

public class AsyncRepository : IAsyncDisposable
{
    public async ValueTask DisposeAsync()
    {
        // асинхронная очистка ресурсов
    }
}

await using var repo = new AsyncRepository();

Паттерн Dispose

  1. public Dispose() - явное освобождение
  2. protected virtual Dispose(bool) - для наследования
  3. ~Финализатор - страховка, если Dispose не вызван
  4. GC.SuppressFinalize() - убираем из очереди финализатора

Лучшие практики

  • Всегда используй using statement для IDisposable
  • Проверяй _disposed перед использованием
  • Поддерживай наследование через protected virtual Dispose
  • Для асинхронной очистки используй IAsyncDisposable
  • Dokumentируй какие ресурсы освобождаются

IDisposable критичен для управления ресурсами и предотвращения утечек в .NET.