В чем разница между Dispose и финализатором в C# и зачем они нужны
Что проверяют
Понимаете ли вы, что одно детерминированное, а другое нет, и знаете ли, что финализатор нужен редко.
Как отвечать
Dispose это явное освобождение: вы сами решаете, когда отпустить ресурс. Вызывается через using или напрямую. Момент известен точно.
Финализатор (~ClassName) вызывает сборщик мусора, и момент неизвестен. Более того, он может не вызваться вовсе при аварийном завершении процесса.
Зачем тогда нужен финализатор: это страховка на случай, если Dispose забыли. Объект с финализатором попадает в очередь финализации, и это дорого: он переживает как минимум одну лишнюю сборку и переезжает в старшее поколение. Поэтому финализатор пишут только там, где класс напрямую владеет неуправляемым ресурсом (дескриптор, указатель), и почти никогда в обычном коде.
Правильная схема выглядит так:
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this); // финализатор больше не нужен
}
protected virtual void Dispose(bool disposing)
{
if (disposing) { /* управляемые ресурсы */ }
/* неуправляемые освобождаем всегда */
}GC.SuppressFinalize здесь ключевой: он снимает объект с очереди финализации, раз ресурс уже освобождён.
Современная практика: для неуправляемых дескрипторов брать SafeHandle, который сам решает вопрос финализации, и не писать финализаторы вручную. Для асинхронного освобождения есть IAsyncDisposable и await using.
Где спотыкаются
Пишут финализатор каждому классу с IDisposable.
Забывают GC.SuppressFinalize и оставляют лишнюю работу сборщику.
Считают, что финализатор гарантированно выполнится.
Освобождают управляемые объекты внутри финализатора, хотя их состояние там уже недостоверно.