В чем разница между использованием IDisposable и деструктором в С#?

Когда я буду реализовывать IDispose в классе, а не деструкторе? Я прочитал эту статью, но я до сих пор не понимаю смысла.

Мое предположение заключается в том, что если я реализую IDispose для объекта, я могу явно "уничтожить" его, а не ждать, пока сборщик мусора сделает это. Правильно ли это?

Означает ли это, что я всегда должен явно вызывать Dispose на объекте? Каковы некоторые общие примеры этого?

Ответ 1

Финализатор (ака деструктор) является частью сбора мусора (GC) - он неопределен, когда (или даже если) это происходит, поскольку GC в основном происходит в результате давления в памяти (т.е. требуется больше места). Финализаторы обычно используются только для очистки неуправляемых ресурсов, поскольку управляемые ресурсы будут иметь свою собственную сбор/удаление.

Следовательно, IDisposable используется для детерминированной очистки объектов, т.е. сейчас. Он не собирает память объекта (который все еще принадлежит GC) - но используется, например, для закрытия файлов, подключений к базе данных и т.д.

Есть много предыдущих тем:

Наконец, обратите внимание, что для объекта IDisposable нередко также есть финализатор; в этом случае Dispose() обычно вызывает GC.SuppressFinalize(this), что означает, что GC не запускает финализатор - он просто отбрасывает память (намного дешевле). Финализатор по-прежнему работает, если вы забудете Dispose() объект.

Ответ 2

Роль метода Finalize() заключается в обеспечении того, чтобы объект .NET мог очистить неуправляемые ресурсы при сборе мусора. Однако такие объекты, как соединения с базой данных или обработчики файлов, должны быть выпущены как можно скорее, вместо этого, опираясь на сборку мусора. Для этого вы должны реализовать интерфейс IDisposable и освободить ресурсы в методе Dispose().

Ответ 3

Существует очень хорошее описание MSDN:

Основное использование этого интерфейса освободить неуправляемые ресурсы. Сборщик мусора автоматически освобождает память, выделенную управляемый объект, если этот объект отсутствует дольше используется. Однако он не можно предсказать, когда мусор будет происходить сбор. Более того, сборщик мусора не имеет знание неуправляемых ресурсовтакие как оконные ручки или открыть файлы и потоки.

Используйте метод Dispose этого интерфейс явно освободитьнеуправляемые ресурсы в совокупности с сборщиком мусора. потребитель объекта может вызывать этот метод, когда объект отсутствует дольше.

Ответ 4

Единственное, что должно быть в деструкторе С#, - это строка:

Dispose(False);

Что это. В этом методе никогда не должно быть ничего другого.

Ответ 5

Ваш вопрос относительно того, следует ли вам всегда называть Dispose, обычно является жарким дебатом. Смотрите этот блог для интересной перспективы от уважаемых людей в сообществе .NET.

Лично я считаю, что позиция Джеффри Рихтера, что вызов Dispose не является обязательным, невероятно слаб. Он дает два примера, чтобы оправдать его мнение.

В первом примере он говорит, что вызов Dispose в элементах управления Windows Forms является утомительным и ненужным в основных сценариях. Однако он не упоминает, что Dispose фактически вызывается автоматически контейнерами управления в этих сценариях основного потока.

Во втором примере он утверждает, что разработчик может ошибочно предположить, что экземпляр из IAsyncResult.WaitHandle должен быть агрессивно настроен, не понимая, что свойство лениво инициализирует дескриптор ожидания, что приводит к ненужному снижению производительности. Но проблема с этим примером заключается в том, что сам IAsyncResult не придерживается собственных опубликованных рекомендаций Microsoft для работы с объектами IDisposable. То есть, если класс содержит ссылку на тип IDisposable, тогда сам класс должен реализовать IDisposable. Если IAsyncResult следовало этому правилу, то его собственный метод Dispose мог бы принять решение о том, какой из его составных членов нуждается в утилизации.

Поэтому, если у кого-то нет более веских аргументов, я собираюсь остаться в лагере "всегда вызывать Dispose" с пониманием того, что будут какие-то случаи, которые возникают в основном из-за плохого выбора дизайна.

Ответ 6

Это довольно просто. Я знаю, что на это был дан ответ, но я попробую еще раз, но постараюсь сделать это как можно проще.

Деструктор вообще никогда не должен использоваться. Он запускается только .net хочет, чтобы он запускался. Он будет работать только после цикла сбора мусора. Это может никогда не запускаться в течение жизненного цикла вашего приложения. По этой причине вы никогда не должны вводить какой-либо код в деструктор, который должен быть запущен. Вы также не можете полагаться на какие-либо существующие объекты в классе, которые существуют при его запуске (они, возможно, уже были очищены, поскольку порядок, в котором работают деструкторы, не гарантируется).

IDisposible следует использовать всякий раз, когда у вас есть объект, который создает ресурсы, требующие очистки (т.е. файлы и графические дескрипторы). На самом деле, многие утверждают, что все, что вы помещаете в деструктор, должно быть установлено в соответствии с перечисленными выше причинами.

Большинство классов вызовут dispose при выполнении финализатора, но это просто существует как безопасный защитник и никогда не следует полагаться. Вы должны явно распоряжаться всем, что реализует IDisposable, когда вы закончите с ним. Если вы реализуете IDisposable, вы должны вызвать dispose в finalizer. См. http://msdn.microsoft.com/en-us/library/system.idisposable.aspx для примера.

Ответ 7

Вот еще одна прекрасная статья, которая очищает часть тумана, окружающего IDisposable, GC и удаляет.

Chris Lyons WebLog Disystifying Dispose