Почему структуры не могут иметь деструкторов?

Какой лучший ответ на собеседовании на такой вопрос вы думаете?

Я думаю, что я не нашел копию этого здесь, если есть, пожалуйста, свяжите это.

4 ответа

Решение

Другой способ взглянуть на это - вместо того, чтобы просто цитировать спецификацию, в которой говорится, что структуры не могут / не имеют деструкторов, - подумать, что произойдет, если спецификация была изменена таким образом, или, скорее, давайте зададим вопрос: can мы догадываемся, почему разработчики языка решили не позволять структурам иметь "деструкторы" в первую очередь?

(Не зацикливайтесь на слове "деструктор" здесь; мы в основном говорим о магическом методе для структур, который вызывается автоматически, когда переменная выходит из области видимости. Другими словами, языковая особенность, аналогичная деструкторам C++.)

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

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

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

Возможно, вы могли бы обойти эту проблему, добавив специальный механизм к операциям присваивания, который каким-то образом позволяет новой структуре договариваться о владении базовым ресурсом с его новой копией - возможно, они делятся им или передают право собственности прямо от старого к новому - но теперь вы По сути, мы отправились в C++- страну, где вам нужны конструкторы копирования, операторы присваивания и добавили кучу тонкостей, ожидающих, чтобы заманить в ловушку начинающего программиста. И имейте в виду, что весь смысл C# состоит в том, чтобы как можно больше избегать такого типа сложности в стиле C++.

И просто чтобы сделать вещи немного более запутанными, как указывал один из других ответов, структуры не просто существуют как локальные объекты. С местными жителями область видения хороша и хорошо определена; но структуры также могут быть членами объекта класса. Когда в этом случае должен вызываться "деструктор"? Конечно, вы можете сделать это, когда класс контейнера будет завершен; но теперь у вас есть механизм, который ведет себя очень по-разному в зависимости от того, где находится структура: если структура является локальной, она запускается сразу в конце области видимости; если структура находится внутри класса, она запускается лениво... Так что если вы действительно заботитесь о том, чтобы какой-то ресурс в одной из ваших структур был очищен в определенное время, и если ваша структура могла бы в конечном итоге стать членом класс, вам, вероятно, понадобится что-то явное, например IDisposable/using(), чтобы убедиться, что ваши базы покрыты.

Поэтому, хотя я не могу претендовать на то, чтобы говорить от имени языковых дизайнеров, я могу сделать довольно хорошее предположение, что одна из причин, по которой они решили не включать такую ​​функцию, заключается в том, что это будет червячная банка, и они хотели сохранить C# достаточно простым.,

От Джона Джаггера:

"Структура не может иметь деструктора. Деструктор - это просто переопределение object.Finalize замаскированный, а структуры, являющиеся типами значений, не подлежат сборке мусора."

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

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

Поскольку по определению деструкторы используются для уничтожения экземпляров классов, а структуры являются типами значений.

Ссылка: http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

По собственным словам Microsoft: "Destructors are used to destruct instances of classes." поэтому немного глупо спрашивать: "Почему вы не можете использовать деструктор (то, что не является классом)?" ^^

Другие вопросы по тегам