Что такое IDisposable и зачем нужен using в C#?
Постоянно вижу using (var conn = ...) и интерфейс IDisposable. Что они делают и почему нельзя просто положиться на сборщик мусора?
using (var file = new StreamReader("data.txt"))
{
// ...
}
2 ответа
GC освобождает только управляемую память. Но есть неуправляемые ресурсы — файловые дескрипторы, сетевые сокеты, подключения к БД — которые GC сам не закроет вовремя (а то и вообще). За них отвечает IDisposable.
IDisposable — это интерфейс с единственным методом Dispose(), где вы освобождаете такие ресурсы. А using гарантирует, что Dispose() вызовется всегда, даже если внутри блока вылетит исключение.
// using разворачивается в try/finally:
var file = new StreamReader("data.txt");
try
{
Console.WriteLine(file.ReadToEnd());
}
finally
{
file.Dispose(); // вызовется в любом случае
}
С C# 8 есть короткий синтаксис без фигурных скобок — ресурс освободится в конце области видимости:
using var file = new StreamReader("data.txt");
Console.WriteLine(file.ReadToEnd());
// Dispose() здесь, на выходе из метода
Правило: всё, что реализует IDisposable, оборачивайте в using.
Если пишете свой класс с неуправляемыми ресурсами, реализуйте IDisposable так:
public class Resource : IDisposable
{
private bool _disposed;
public void Dispose()
{
if (_disposed) return;
// освобождаем ресурсы
_disposed = true;
GC.SuppressFinalize(this);
}
}
Для асинхронного освобождения (например, потоков) есть IAsyncDisposable и await using.