Деструктор против IDisposable?

Я читал об утилизации объектов / IDisposable интерфейса и деструкторов в C #, но для меня они, похоже, делают то же самое?

Какая разница между двумя? Почему я должен использовать один над другим? Фактически, в этом примере (ссылка ниже) этот код использует как интерфейс IDisposable, так и деструктор:

http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

В комментарии говорится, что деструктор – это если код завершения не используется, но как я могу решить, когда использовать один над другим?

Я написал довольно подробный пост, который должен помочь объяснить о финализаторах, IDisposable и когда вы должны использовать тот или иной: http://gregbee.ch/blog/implementing-and-using-the-idisposable-interface

Вероятно, наиболее важная часть приведена ниже:

Когда вы используете неуправляемые ресурсы, такие как ручки и соединения с базой данных, вы должны следить за тем, чтобы они удерживались на минимальный период времени, используя принцип позднего оповещения и освобождения на ранней стадии. В C ++ освобождение ресурсов обычно выполняется в деструкторе, который детерминированно выполняется в точке, где объект удален. Однако среда выполнения .NET использует сборщик мусора (GC) для очистки и восстановления памяти, используемой объектами, которые больше недоступны; поскольку это выполняется периодически, это означает, что точка, в которой ваш объект очищается, является недетерминированным. Следствием этого является то, что деструкторы не существуют для управляемых объектов, поскольку нет детерминированного места для их запуска.

Вместо деструкторов C # имеет финализаторы, которые реализуются путем переопределения метода Finalize, определенного в базовом classе Object (хотя C # несколько смущает использование синтаксиса деструктора C ++ ~ Object для этого). Если объект переопределяет метод Finalize, а не собирает GC, когда он выходит за пределы области видимости, GC помещает его в очередь финализатора. В следующем цикле GC запускаются все финализаторы в очереди (в одном streamе текущей реализации) и память от завершенных объектов. Это довольно очевидно из-за этого, почему вы не хотите выполнять очистку в финализаторе: для сбора объекта вместо одного требуется два цикла GC, и есть один stream, в котором все финализаторы запускаются, пока все остальные streamи приостановлены, поэтому это повредит работе.

Поэтому, если у вас нет деструкторов, и вы не хотите оставлять очистку до финализатора, тогда единственный вариант – вручную, детерминированно очищать объект. Введите интерфейс IDisposable, который предоставляет стандарт для поддержки этой функции и определяет единственный метод Dispose, где вы вставляете логику очистки для объекта. При использовании в конечном блоке этот интерфейс обеспечивает эквивалентную функциональность деструкторам. Причина для окончательных блоков в коде в первую очередь заключается в поддержке интерфейса IDisposable; поэтому C ++ использует просто try / except, поскольку нет необходимости в блоке finally с деструкторами.

Укороченная версия

Финализатор дает вам возможность избавиться от неуправляемых ресурсов, если пользователь вашего объекта забыл вызвать IDisposable.Dispose .

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


Мой самый популярный ответ на Stackoverflow позволяет вам с самого начала понять, почему у вас есть IDisposable, что он должен делать, что может сделать ваш финализатор, чего он не должен делать.

Этот ответ тает лицом

был использован для его описания: P

Наличие деструктора (~ Object ()) в управляемом языке программирования является самой дурной идеей. Для неуправляемых языков, таких как C, C ++, совершенно разумно иметь деструкторы, поскольку они используют идиому RAII, но для управляемых, таких как Java, C #, настолько абсурдны.

Напомним, что Джошуа Блох (Joshua Bloch), бывший руководитель проекта в Java Collection Framework, считает, что идея метода finalize (), эквивалентная C ++ как деструктор C ++, была самой большой ошибкой. То же, что и в C #, finallize () в Java дает накладные расходы «новым», так как он должен быть добавлен в очередь финализатора при распределении. Более того, сборщик мусора должен появиться и запустить finallize () в очереди, так что дважды накладные расходы во время gc.

У C # было много улучшенных функций, таких как «использование (IDisposable) {}», которые не только позволяют ограничивать IDisposable переменную для области «использования», но также гарантировать ее очистку. Мой вопрос: почему C # следовали одному и тому же пути Java, что привело к большой ошибке. Может быть, если развитие dotnet началось после 2003 ~ 2005 года, когда многие архитекторы Java обнаружили ошибку finallize (), тогда ошибка была бы предотвращена.

Многие хорошие идеи одного языка часто переносятся на другой язык, такой как «IDisposable / using combo» в C #, который был перенесен на Java 1.7 в свой оператор try (object-to-dispose) {} “. Но его слишком плохо, что языковые архитекторы не могут обнаружить плохую идею, замаскированную под хорошую идею во время ее передачи от одного к другому.

Мой совет никогда не должен использовать ~ Destructor () и придерживаться IDisposable / using combo, если вам нужно вручную очистить неуправляемый ресурс, например, соединения с базой данных.

  • Уничтожить stream массива json по одному элементу за раз
  • Как определить, включен ли возвращенный указатель в стек или кучу
  • c # преобразовать строковое выражение в логическое выражение
  • Удалить , равное удалению?
  • Как отправить JSON на сервер?
  • Когда следует использовать static_cast, dynamic_cast, const_cast и reinterpret_cast?
  • «Int size = 10;» дает постоянное выражение?
  • Взаимодействие с classами C ++ из Swift
  • Как преобразовать имена переименований в строку в c
  • printf не печатать на консоли
  • Производительность C ++ по сравнению с Java / C #
  • Interesting Posts

    Можно ли заполнить массив номерами строк, которые соответствуют определенным критериям без цикла?

    Несколько стандартных входных сигналов? Как?

    MacOSX. Возможно ли иметь два интернет-соединения на одном компьютере?

    Разница между require, include, require_once и include_once?

    Изменение всех системных шрифтов в Windows 7

    Как преобразовать дерево выражений в частичный запрос SQL?

    Как создать надстройку автоматизации Excel в режиме реального времени на C # с помощью RtdServer?

    Пакет Hibernate Mapping

    Удалить столбец из pandas DataFrame с помощью del df.column_name

    Быстрый потолок целочисленного деления в C / C ++

    Действительно ли опечатанные classы действительно предлагают преимущества?

    Как прокручивать вверх в окне терминала, в то время как новый ввод генерируется без отбрасывания назад (внизу)

    MySqlCommand Command.Parameters.Add устарел

    glVertexAttribPointer и glVertexAttribFormat: В чем разница?

    Где Google Chrome для Linux хранит пользовательские данные?

    Давайте будем гением компьютера.