2009-03-05 8 views
17

Если .NET имеет сборку мусора, то почему вы должны явно позвонить IDisposable?Что такое IDisposable?

+2

Существует много существующих ответов на этот вопрос, если вы помещаете IDisposable в поле поиска. –

ответ

46

Сбор мусора для памяти. Вам нужно избавиться от ресурсов, отличных от памяти: дескрипторов файлов, сокетов, дескрипторов GDI +, подключений к базе данных и т. Д. Обычно это относится к типу IDisposable, хотя фактический дескриптор может быть довольно длинным вниз по цепочке ссылок. Например, вы можете Dispose a XmlWriter, который располагает StreamWriter, к которому относится ссылка, в которой находится FileStream, на которой имеет ссылку на, которая сама выпускает дескриптор файла.

5

Потому что объекты когда-то хранят ресурсы рядом с памятью. GC выпускает память; IDisposable - значит, вы можете выпускать что-нибудь еще.

1

потому что вы хотите контролировать, когда ресурсы, удерживаемые вашим объектом, будут очищены.

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

Это когда используется IDisposable. Вызовите Dispose() явно (или используя синтаксический сахар используемого блока), вы можете получить доступ к вашему объекту, чтобы очистить себя стандартным способом (т. Е. Вы могли бы реализовать свой собственный вызов cleanup() и вызвали это явно)

Примеры ресурсов, которые вы хотели бы очистить, это: дескрипторы баз данных, дескрипторы файлов, сетевые ручки.

8

Расширение немного на другие комментарии:

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

Тем не менее, некоторые другие вещи, чтобы иметь в виду:.

  • Calling отчуждать не дает вам контроль над когда объект фактически уничтожен и память выпустила GC ручки, что для нас, и делает это лучше, чем мы можем
  • . Dispose очищает все собственные ресурсы, вплоть до стека базовых классов, как указал Джон. Затем он вызывает SuppressFinalize(), чтобы указать, что объект готов быть исправлены и дальнейшая работа не требуется. Следующий запуск GC очистит его.
  • Если Dispose не вызывается, GC обнаруживает объект, который должен быть очищен, но сначала необходимо вызвать Finalize, чтобы убедиться, что ресурсы выпущены, этот запрос для Finalize находится в очереди и GC перемещается, поэтому Отсутствие вызова Dispose заставляет еще один GC работать до того, как объект может быть очищен. Это заставляет объект продвигаться к следующему «поколению» GC. Это может показаться не очень важным, но в приложении с напряжением памяти продвижение объектов до более высоких поколений GC может подтолкнуть приложение с высокой памятью к стене, чтобы стать приложением с отсутствием памяти.
  • Не используйте IDisposable в своих собственных объектах, если вам абсолютно не нужно. Плохо реализованные или ненужные реализации могут фактически ухудшить ситуацию, а не лучше.Некоторые хорошие рекомендации можно найти здесь:

    Implementing a Dispose Method

    Or read that whole section of MSDN on Garbage Collection

+0

Re: «Не реализуйте IDisposable ... если вам абсолютно не нужно» - просто будьте осторожны при определении интерфейсов - если есть вероятность, что реализация интерфейса может потребовать удаления, тогда интерфейс должен быть idisposable с самого начала. В противном случае все клиенты будут нуждаться в рефакторинге. – morechilli

+0

+1 для хорошего и более тщательного ответа. Я подозреваю, что предупреждение о том, что вы не реализуете что-либо, если вы не должны больше указывать на 'Finalize()', чем 'Dispose()'. –

+0

Цель «IDisposable» - предоставить стандартное средство, позволяющее знать объекты, когда их услуги больше не требуются. Это, в свою очередь, позволяет им уведомлять другие объекты, службы которых они использовали, что услуги других объектов больше не требуются. Объекты, которые заботятся, когда их службы больше не требуются, должны реализовывать 'IDisposable'. Объектам, которые владеют другими объектами, которые заботятся о том, когда они больше не нужны, также должны реализовывать «IDisposable», чтобы они могли пересылать уведомления «больше не нужны» для этих внутренних объектов. – supercat

0

Интерфейс IDisposable часто описывается с точки зрения ресурсов, но большинство таких описаний не могут действительно учитывать, что означает «ресурс».

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

В целом, объект X, который просит сущность что-то предпринять, до тех пор, пока дальнейшее уведомление не примет на себя обязательство предоставить такое уведомление, но не может доставить такое уведомление, если клиент X может нуждаться в услугах X. Цель IDisposable - обеспечить единый способ информирования объектов о том, что их услуги больше не требуются, чтобы они могли уведомлять сущности (если они есть), действующие от их имени, что их услуги больше не требуются. Код, который вызывает IDisposable, не нуждается ни в том, чтобы знать, ни заботиться о том, какие (если есть) услуги запрашивал объект у внешних объектов, так как IDisposable просто приглашает объект выполнять обязательства (если есть) для внешних объектов.

Чтобы передать вещи в терминах «ресурсы», объект приобретает ресурс, когда он просит внешний объект делать что-то от его имени (как правило, хотя и необязательно, предоставляя исключительное использование чего-либо) до дальнейшего уведомления и выпуска ресурс, когда он сообщает этому внешнему сущности, что его услуги больше не требуются. Код, который приобретает ресурс, не получает «вещи», поскольку он несет обязательство; освобождение ресурса не отказывается от «вещи», но вместо этого выполняет обязательство.