1
votes

I have a COM object implemented in C# (see below). It owns some IDisposable resource. Where should I dispose that resource?

Looks like finalizer is never called and I cannot overload IUnknown::Release method.

[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");
    }
}

Edited: the COM server is used in a native third party application, it's impossible to call Dispose on client side or make any changes there.

2
This question is really just a dupe of either How to dispose of a NET COM interop object on Release() or RCW & reference counting when using COM interop in C#. Short version: .NET COM wrappers keep a ref-count on your COM object so even if you could intercept Release(), you'd never see the ref-count go to zero. Your clients will need to call Dispose() explicitly.Peter Duniho
Note that if it makes sense for your server interface to have a Dispose() or Close() method then you can just put the method there. Otherwise, you'll want to have clients query for IDisposable and get the Dispose() method from there. This is explained in more detail in those other two questions.Peter Duniho

2 Answers

0
votes

There is no guarantee when of if the finalize will be called. Your ComServer should implement the IDiposable interface itself and release it's disposable members within it.

From MSDN (if you override Object.Finalize)

If you are defining a base class that uses unmanaged resources and that either has, or is likely to have, subclasses that should be disposed, you should implement the IDisposable.Dispose method and provide a second overload of Dispose, as discussed in the next section.

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);
   }
}

Then call Dispose explicitly if you need it disposed or use using where ever possible.

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

Finalizer will never be called if your object is not marked for garbage collection. Go and look for the reason. As to Dispose, only you can decide when to dispose your objects. It depends on the architecture, lifecycle of your objects. Generally speaking, you should call Dispose() when the object is no longer needed.

The best thing you can do is to implement IDisposable on your ComServer and invoke Dispose where your objects are no longer needed, or you can just wrap them in using constructions.

Tseng provided an example of standard implementation of IDisposable pattern, though consider that a good program does not need finalizers. Generally, it's a bad practice to leave your objects with intention to rely upon the mechanism of finalizing.

If you want to test your finalizer, than you can create your object, do not dispose it, call GC.Collect(). This call will force the garbage collection and if your object is eligible for garbage collection your finalizer will be invoked. But just remember never to use GC.Collect() as part of your production code.