2013-06-06 2 views
5

У меня есть класс C++/CLI под названием «CTransferManaged» с реализованной финализацией и деструктором:C#/CLI: Деструктор не вызывается, если Dispose(), используемым в ней

CTransferManaged::~CTransferManaged() 
{ 
    this->!CTransferManaged(); 
} 
CTransferManaged::!CTransferManaged() 
{ 
    //Clean up resources... 
} 

Этого класс обернут с C# класса по имени «CTransfer» содержит объект m_transfer типа CTransferManaged.

Если деструктор этого класса удаляет только ссылку на объект m_transfer я могу видеть, что деструктор (точка останова):

~CTransfer() 
{ 
    m_transfer = null; //breakpoint on this line 
} 

Если я вызываю функцию Dispose() в m_transfer объект без изменения чего-либо еще, деструктор больше не вызывается (точка останова больше не попадает). Какие-нибудь догадки почему?

~CTransfer() 
{ 
    m_transfer.Dispose(); //breakpoint on this line 
    m_transfer = null; 
} 

Я хотел бы назвать Dispose() вручную, так как я узнал, что ресурсы объекта C++/CLI (m_transfer) не очищены должным образом, если я не называю Dispose вручную. На данный момент я точно не знаю, почему.

Почему деструктор CTransfer (класс C#) больше не вызван, как только он вызывает CTransferManaged :: Dispose() (C++/CLI)?

+0

Ваш класс CTransfer * должен * реализовать IDisposable, чтобы он мог правильно распоряжаться членом m_transfer. Похоже, ты это сделал. Do ** not ** реализовать финализатор для CTransfer. Установка члена в null не имеет никакого полезного эффекта, и вызов метода Dispose() просто неверен. –

+0

@HansPassant: Почему неправильный вызов метода Dispose() объекта-члена (m_transfer) в финализаторе CTransfer? Как я уже упоминал, я выяснил, что ресурсы m_transfer не очищаются должным образом, когда я не вызываю Dispose() на нем ( obruend

ответ

0

C# destructor только вызывается сборщиком мусора, и вы не можете назвать его напрямую.

Утилизировать, который является частью интерфейса IDisposalbe, должен вызываться только вручную, и он не будет запускать деструктор.

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

Если класс Resource содержит встроенные объекты, которые должны быть утилизированы, эта модель необходима с C#:

// C# 
public class Resource : IDisposable 
{ 
    private EmbeddedResource embedded; 

    public Resource() 
    { 
     Console.WriteLine("allocating resource"); 
     embedded = new EmbeddedResource(); 
    } 

    ~Resource() 
    { 
     Dispose(false); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     Console.WriteLine("release resource"); 
     if (disposing) 
     { 
     embedded.Dispose(); 
     } 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
    } 
} 
+0

Обратите внимание, что я не хочу вручную Dispose() объект C# (класс CTransfer). Я просто хочу использовать ручное удаление своего члена m_transfer (класс CTransferManaged), так как его ресурсы не очищаются должным образом в противном случае. – obruend

0

Характерные для Располагая и финализация такова, что при вызове Dispose, финализации должны быть подавлены , Dispose предназначен для очистки ресурсов, как только он выполняется, тогда как финализатор предназначен для очистки ресурсов всякий раз, когда сборщик мусора собирает класс ... Оба предназначены для того, чтобы делать то же самое (освобождать неуправляемые ресурсы), и поэтому, если вы вызываете Dispose, вызов finalizer будет излишним и ненужным, а также приведет к тому, что объект будет жить дольше, чем нужно, поскольку он сначала будет помещен в очередь Finalizer перед сборкой и уничтожением. Это приводит к плохому управлению памятью в приложениях с высоким доступом, которые создают и удаляют многие объекты. Таким образом, наиболее Dispose методы в C# будут называть:

GC.SuppressFinalize(this); 

Который говорит сборщик мусора не делать финализатор. Этот шаблон широко используется и, вероятно, также используется в вашем неуправляемом классе. Вероятно, поэтому вызов Dispose устраняет деструктор.

Смежные вопросы