Наследования, а деструкторы в C#

По данным этой говорится, что Destructors cannot be inherited or overloaded. в моем случае, для всех подклассов, деструкторы будут идентичны. Это в значительной степени говорит мне, что я должен определить один и тот же деструктор в каждом подклассе. Нет никакого способа, которым я могу объявить деструктор в базовом классе и ручку разрушения? Скажем, у меня есть что-то вроде этого:

class A
{
    ~A()
    {
        SomethingA();
    }

}

class B : A
{

}

B b = new B();

, когда B его деструктора не назовешь?

6 ответов


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

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

в моем случае, для всех подклассов, деструкторы будут идентичны.

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

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

нет, вовсе нет. Как вы пришли к такому выводу из того, что деструкторы не унаследовал?

нет никакого способа, которым я могу объявить деструктор в базовом классе и ручку разрушения?

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

Когда б его деструктора не назовешь?

Это неверно.

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

когда деструкторы действительно вызываются? Это на сборке мусора, когда переменная выпадает из области видимости?

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

когда объект определяется как недоступный из корня gc сборщиком, и объект имеет финализатор, который не был подавлен, тогда объект повышается до следующего поколения, помещая его в очередь завершения для обслуживания потоком финализатора. Если нет, его память восстанавливается.

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

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

этот ответ может помочь:

когда я должен создать деструктор?


Это не деструктор в C#. Он известен как Финиализатор; и когда он вызывается, он недетерминирован. Вы вообще не можете рассчитывать на то, что он будет вызван.

финализаторы используются в качестве последнего средства для очистки неуправляемых ресурсов. Вы должны посмотреть в Dispose pattern.


финализатор, определенный В A, будет вызываться при уничтожении экземпляра B.

Если вы определяете финализатор как в A, так и в, Сначала будет запущен наиболее конкретный финализатор (B), а затем наименее конкретный (A).


Я занимаюсь .NET-программированием почти десять лет. The только раз я реализовал финализатор, он оказался причиной утечки памяти и ничего больше. Они почти никогда не нужны.


Если вы определяете деструктор для B, он будет вызываться, а затем A. Смотрите пример внизу предоставленной вами ссылке.


Ну, я не знаю о деструкторах, но у вас есть другие полезные методы для очистки, такие как Finalize() и Dispose() из IDisposable.