В чем разница между деструктором и методом завершения?

Сегодня будет еще один диалог и еще один эпизод из моей постоянной рубрики «в чем разница?».

В чем разница, если она вообще существует, между «деструктором» ( destructor ) и «методом завершения» (finalizer)?

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

Означает ли это, что в спецификации C# термин «деструктор» используется некорректно?

Да, согласно этому определению, в спецификации C# допущена ошибка. То, что в спецификации называется «деструктором» на самом деле является «методом завершения», а то, что мы называем вызовом метода “Dispose()” при выходе из блока “using”, по сути, является «деструктором».

В спецификации CLI метод завершения называется правильно.

Почему авторы спецификации C# допустили такую ошибку?

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

Догадка №1 заключается в том, что 12 мая 1999 года еще не было статьи в Википедии ясно описывающей тонкие различия между этими двумя понятиями. Потому что не было тогда еще Википедии. Помните то далекое прошлое, когда не было Википедии? Темные времена, дружище. Ошибка просто заключается в невинном заблуждении, что эти два термина равнозначны.

Черт возьми! Я думаю, что 12 мая 1999 года эти термины значили одно и то же, а различия в определениях появилась позже, когда стало очевидно, что нужно различать методы принудительной/детерминированной и ленивой/недетерминированной очистки ресурсов. Если кто-то лучше меня знает историю того времени, не стесняйтесь, присоединяйтесь к дискуссии.

Предположение №2 заключается в том, что 12 мая 1999 года, комитет по проектированию языка C# хотел оставить возможность, чтобы деструктор был реализован не только как метод завершения CLR. Т.е. «деструктор», как концепция языка программирования C#, не обязан в точности соответствовать концепции «метода завершения» CLR.

При одновременном проектировании языка программирования и инфраструктуры (framework), на которой основан этот язык, порой возникает желание защитить себя от разрушительных изменений подсистем на поздних стадиях. Один из способов добиться этого – преднамеренное разделение имен.

Что у вас за одержимость 12 мая 1999 года?

Заметка комитета по стандартизации языка от 12 мая 1999 года:

”Мы собираемся использовать термин «деструктор» в качестве названия метода, который будет выполняться при освобождении объекта. Деструкторы могут быть только у классов, структуры содержать деструкторы не могут. В отличие от С++, явный вызов деструктора невозможен. Время вызова деструктора не определено – вы не можете точно знать, когда деструктор будет вызван, но вы можете точно сказать, что он будет выполнен после освобождения всех ссылок на объект. В случае иерархии наследования деструкторы вызываются в порядке от самых дальних наследников к ближним. Нет необходимости (и не существует способа) для класса наследника явно вызвать деструктор базового класса. Компилятор C# компилирует деструкторы в соответствующее представление для CLR. Для данной версии это, вероятно, означает метод завершения экземпляра, указанный в метаданных.”

Обратите внимание, что это подтверждает мое предположение о том, что команда проектирования языка пыталась оградить себя от привязки к конкретному термину CLR.

Оригинал статьи