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

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

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

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

7 ответов


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

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

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

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


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


есть очень хорошее описание по MSDN:

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

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


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

Dispose(False);

вот и все. Ничего другого не должно быть в этом методе.


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

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

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

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

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


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

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

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

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


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

Крис Лайонс Веблог Демистификация Dispose