В чем разница между использованием IDisposable и деструктором в C #? - PullRequest
92 голосов
/ 04 декабря 2008

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

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

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

Ответы [ 7 ]

115 голосов
/ 04 декабря 2008

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

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

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

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

23 голосов
/ 04 декабря 2008

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

9 голосов
/ 04 декабря 2008

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

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

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

8 голосов
/ 04 декабря 2008

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

Dispose(False);

Вот и все. В этом методе больше не должно быть ничего.

4 голосов
/ 09 сентября 2009

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

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

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

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

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

2 голосов
/ 04 декабря 2008

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

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

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

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

0 голосов
/ 09 сентября 2009

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

Chris Lyons WebLog Демистифицирующая утилизация

...