Самое близкое, что есть в .NET к деструктору, это то, что .NET называет финализатором. Основное отличие состоит в том, что деструктор обычно имеет детерминированную финализацию (скажем, когда счетчик ссылок на объект становится равным нулю), а финализатор .NET вызывается через неопределенное время после того, как на объект больше не ссылаются. Это обрабатывается сборщиком мусора .NET с использованием процедуры трассировки корней, а не с помощью простого подсчета ссылок.
Одна из лучших статей на эту тему - Сборка мусора: автоматическое управление памятью в Microsoft .NET Framework . Подробнее о финализаторах см. Статью Финализация методов и деструкторов в MSDN.
Разве я не могу получить доступ к закрытому классу?
члены в деструкторе?
Нет, вы не можете сделать это безопасно.
В вашем случае происходит то, что, когда корень больше не имеет прямой или косвенной ссылки на ваш объект, COM-объекты, на которые ссылается ваш объект, то есть объекты, на которые ссылаются ваши личные поля, также не упоминаются корнем либо. (Ссылка на поля вашего объекта не поддерживает эти COM-объекты живыми, потому что на ваш объект больше не ссылается или не отслеживает корень, и, следовательно, COM-объекты также не отслеживаются от корня .) Таким образом, ваш объект и все COM-объекты, на которые он ссылается, готовы к сборке мусора одновременно . Некоторое время спустя сборщик мусора очистит ваш объект и вызовет его финализатор, как это будет происходить и с COM-объектами, каждый из которых действительно является Runtime Callable Wrapper (RCW) .
Проблема в том, что не только время, когда эти объекты подлежат сборке мусора, является неопределенным, но и порядок , в котором вызываются финализаторы, также недетерминирован. В этом случае Runtime Callable Wrapper также имеет финализатор, который сам вызывает Marshal.ReleaseComObject , что приводит к уменьшению счетчика ссылок на стороне COM ограждения, так что этот объект COM может быть вышел. Но так как порядок вызова финализаторов неясен, вполне возможно, что финализаторы для COM-объектов, на которые ссылаются ваши объекты, будут запускать до финализатора для вашего объекта. Таким образом, код в вашем финализаторе может иногда работать , но, в большинстве случаев, одному или нескольким из вызываемых оболочек среды выполнения, для которых ссылки на ваши объекты уже будут вызывать свои финализаторы, и базовый COM-объект будет иметь выпущен до того, как ваш финализатор выполнит свой код.
Короче говоря, вам следует избегать использования финализаторов вообще, и вы никогда не должны обращаться к ссылочным типам из финализатора, потому что эти ссылочные типы, возможно, уже были завершены.
Чтобы исправить вашу ситуацию, я бы рассмотрел две разные возможности:
Утилизируйте COM-объекты в том же методе, который их создает. У меня есть пара дискуссий по этому вопросу здесь и здесь .
Включите детерминированное удаление вашего объекта, используя IDisposable интерфейс , вместо того, чтобы полагаться на недетерминированный финализатор.
Статьи о том, как реализовать шаблон IDisposable, см .:
- Майк