【问题标题】:Where should a C# COM server call dispose its resources?C# COM 服务器调用应该在哪里处理它的资源?
【发布时间】:2015-05-08 02:05:51
【问题描述】:

我有一个用 C# 实现的 COM 对象(见下文)。它拥有一些IDisposable 资源。我应该在哪里处置该资源?

看起来终结器从未被调用,我无法重载 IUnknown::Release 方法。

[ComVisible(true)]
[Guid("1992EC2F-087A-4264-B5B2-5E2E757F1A75")]
public class ComServer
{
    IDisposable disposableResource; //where to dispose IDisposable resource?
    public ComServer() 
    {
        disposableResource = File.Open(@"c:\somefile.txt", FileMode.OpenOrCreate); 
        Console.WriteLine("ComServer.ComServer");
    }
    ~ComServer() //finalizer is never called!
    {
        disposableResource.Dispose(); 
        Console.WriteLine("ComServer.~ComServer");
    }
}

已编辑:COM 服务器用于本机第三方应用程序,无法在客户端调用 Dispose 或在那里进行任何更改。

【问题讨论】:

  • 这个问题实际上只是How to dispose of a NET COM interop object on Release()RCW & reference counting when using COM interop in C# 的欺骗。简短版本:.NET COM 包装器在您的 COM 对象上保留一个引用计数,因此即使您可以拦截 Release(),您也永远不会看到引用计数变为零。您的客户需要明确致电Dispose()
  • 请注意,如果您的服务器接口有 Dispose()Close() 方法是有意义的,那么您可以将方法放在那里。否则,您需要让客户查询IDisposable 并从那里获取Dispose() 方法。这在其他两个问题中有更详细的解释。

标签: c# com com-interop


【解决方案1】:

无法保证何时调用 finalize。您的 ComServer 应该自己实现 IDiposable 接口并在其中释放它的一次性成员。

来自MSDN(如果您覆盖Object.Finalize

如果您要定义一个使用非托管资源的基类,并且 具有或可能具有应具有的子类 处置,您应该实现 IDisposable.Dispose 方法和 提供 Dispose 的第二个重载,如下所述 部分。

class BaseClass : IDisposable
{
   // Flag: Has Dispose already been called? 
   bool disposed = false;

   // Public implementation of Dispose pattern callable by consumers. 
   public void Dispose()
   { 
      Dispose(true);
      GC.SuppressFinalize(this);           
   }

   // Protected implementation of Dispose pattern. 
   protected virtual void Dispose(bool disposing)
   {
      if (disposed)
         return; 

      if (disposing) {
         // Free any other managed objects here. 
         //
      }

      // Free any unmanaged objects here. 
      //
      disposed = true;
   }

   ~BaseClass()
   {
      Dispose(false);
   }
}

然后,如果您需要处理它,请显式调用 Dispose 或尽可能使用using

using(ComServer com = new ComServer()) {
    // operate on the ComServer
} // Dispose will be called automatically when the leaving the using block

【讨论】:

  • 感谢您的回答!不幸的是 com 客户端是一个原生的第三方应用程序,所以实现 IDisposable 没有意义
【解决方案2】:

Finalizer 如果你的对象没有被标记为垃圾回收,则永远不会被调用。去寻找原因。 至于Dispose,只有您可以决定何时处置您的对象。这取决于对象的体系结构和生命周期。一般来说,当不再需要该对象时,您应该调用Dispose()

您可以做的最好的事情是在您的ComServer 上实现IDisposable 并在不再需要您的对象的地方调用Dispose,或者您可以将它们包装在using 构造中。

Tseng 提供了IDisposable 模式的标准实现示例,尽管认为好的程序不需要终结器。一般来说,让您的对象有意依赖终结机制是一种不好的做法。

如果你想测试你的终结器,而不是你可以创建你的对象,不要释放它,调用GC.Collect()。此调用将强制进行垃圾收集,如果您的对象有资格进行垃圾收集,您的终结器将被调用。但请记住永远不要将GC.Collect() 用作生产代码的一部分。

【讨论】:

    猜你喜欢
    • 2018-04-08
    • 1970-01-01
    • 2014-12-25
    • 1970-01-01
    • 2011-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-19
    相关资源
    最近更新 更多