c# /CLI:如果在其中使用Dispose(),则不调用析构函数

C#/CLI: Destructor not called if Dispose() used in it

本文关键字:析构函数 调用 Dispose CLI 如果 在其中      更新时间:2023-10-16

我有一个名为"CTransferManaged"的c++/CLI类,实现了终结器和析构器:

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

这个类被一个名为"CTransfer"的c#类包装,该类包含一个类型为CTransferManaged的m_transfer对象。

如果该类的析构函数只清除对对象m_transfer的引用,则可以看到析构函数被调用(击中断点):

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

如果我调用m_transfer对象的Dispose()函数而不更改任何其他内容,则不再调用析构函数(不再击中断点)。猜猜为什么?

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

我想手动调用Dispose(),因为我发现c++/CLI对象(m_transfer)的资源没有被正确清理,如果我不手动调用Dispose。现在我不知道确切的原因。

为什么CTransfer (c#类)的析构函数不再调用CTransferManaged::Dispose() (c++/CLI)?

c#析构函数只能由垃圾回收器调用,不能直接调用

Dispose是idisposalable接口的一部分,只能手动调用,它不会触发析构函数。

不要依赖析构函数,尝试实现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);
   }
}

处置和终结的典型模式是这样的:当调用处置时,终止器应该被抑制。Dispose的目的是在执行时立即清除资源,而终结器的目的是在垃圾收集器收集类时清除资源……两者的目的都是做同样的事情(释放非托管资源),因此,如果调用Dispose,调用终结器将是多余和不必要的,并且还会导致对象的生存时间比它需要的更长,因为它在被收集和销毁之前首先被放置在终结器队列中。这会导致高访问应用程序的内存管理不佳,这些应用程序会创建和处理许多对象。因此,c#中的大多数Dispose方法将调用:

GC.SuppressFinalize(this);

告诉垃圾收集器不执行终结器。此模式被广泛使用,并且很可能也在非托管类中使用。这可能就是Dispose调用消除析构函数的原因。