Деструктор против IDisposable?
Я читал об утилизации объектов / IDisposable интерфейса и деструкторов в C #, но для меня они, похоже, делают то же самое?
Какая разница между двумя? Почему я должен использовать один над другим? Фактически, в этом примере (ссылка ниже) этот код использует как интерфейс IDisposable, так и деструктор:
http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
- #pragma once vs include охранники?
- Атомные операции, std :: atomic и упорядочение записи
- Что означает «unsigned temp: 3» в структуре или объединении?
- Как лучше всего отключить предупреждение о неиспользуемых переменных?
- Как BLAS получает такую экстремальную производительность?
В комментарии говорится, что деструктор – это если код завершения не используется, но как я могу решить, когда использовать один над другим?
- Как проверить нули в глубоком lambda-выражении?
- Конец файла (EOF) стандартного входного streamа (stdin)
- Как ограничить доступ к вложенному члену classа включению classа?
- 3 плюс символы между двумя переменными (например, +++ b) в C
- Могу ли я использовать компилятор C ++ Visual Studio 2010 с Visual Studio 2008 C ++ Runtime Library?
- iTextSharp - отправка PDF в формате PDF в приложении электронной почты
- WPF Combobox: различные шаблоны в текстовом поле и выпадающем списке
- Есть ли существенная разница между использованием if / else и switch-case в C #?
Я написал довольно подробный пост, который должен помочь объяснить о финализаторах, 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, если вам нужно вручную очистить неуправляемый ресурс, например, соединения с базой данных.