Implementing IDisposable on Types which Own an IDisposable

Implementing IDisposable on Types which Own an IDisposable
   Implementing IDisposable is a subject discussed so many times that it is highly unlikely I have anything to add that is not common knowledge. However checking the whole first page of Google results did not yield any article that mentions how to implement IDisposable on objects that own an IDisposable object. While the actual code is simple I have seen people forget to implement it or use the unnecessarily heavy Disposable pattern to implement it. But first…

Why We Need IDisposable


   Before we proceed we will revisit the basics. Implementing IDisposable or more precisely calling Dispose() is needed so that unmanaged resources can be released. Usually unmanaged resources are things owned by the OS like file handles, network connections, GDI objects, etc. What happens if we forget to Dispose()? First of all we need to know that if the Disposable Pattern is implemented correctly the object will eventually be disposed when the GC collects it. Then why do we need to call Dispose? The GC collects based on memory pressure so if there is no need to free memory the GC may decide to not collect the object for the whole lifetime of the program. This may result in weird behavior. For example your program might open a file and not dispose the handle so the OS will think your program still needs the file. When this happens the file cannot be deleted or moved and this can be quite annoying and sometimes problematic. In addition many of the resources we use have a finite limit or associated cost. For example if we do not dispose database connections then we may starve the database for connections and prevent other users or our own application from being able to connect. Recall that the GC will happily do nothing if there is enough free memory. Still it is better to dispose when the object is collected than to never dispose. Enter the Disposable pattern.

The Disposable Pattern


   The whole purpose of the Disposable pattern is to make sure the object can be disposed both by calling the Dispose() method and by the GC if the object is connected. The latter is a kind of safety net in case we forget to dispose manually. The way the Disposable pattern accomplishes this is by implementing a Finalizer. Objects that have a Finalizer are not collected immediately after the object is marked for deletion but are put on a finalization queue. They are deleted only after their Finalizer is called. Note that this means that objects with finalizers require more work than regular objects so it is not a good idea to implement a finalizer without a good reason. To fight the performance hit the Disposable pattern calls the GC.SuppressFinalize method when the object is disposed manually. I will not go into details how the Disposable pattern works but I will paste the code here for completeness. If you need to learn about it there is an infinite number of articles about it.

public class ComplexResourceHolder : IDisposable
{
   private IntPtr buffer; // unmanaged memory buffer
   private SafeHandle resource; // disposable handle to a resource
       
   public ComplexResourceHolder()
   {
       this.buffer = ... // allocates memory
       this.resource = ... // allocates the resource
   }

   protected virtual void Dispose(bool disposing)
   {
       ReleaseBuffer(buffer); // release unmanaged memory
       if (disposing)
       {
           // release other disposable objects
           if (resource!= null) resource.Dispose();
       }
   }

   ~ ComplexResourceHolder()
   {
       Dispose(false);
   }

   public void Dispose()
   {
       Dispose(true);
       GC.SuppressFinalize(this);
   }
}

Objects That Own an IDisposable Object


   Sometimes we have an object that holds an unmanaged resource. In this case the correct thing to do is implement the Disposable pattern. However in my career what I encounter much more often is that I need to implement the interface on objects that do not hold unmanaged resources directly but contain another IDisposable object. Take for example the Repository pattern. When implementing a Repository one may decide to hold a database connection or an ORM data context inside the repository object. In this case we need the repository to be IDisposable so the user can dispose it and in this way dispose the underlying unmanaged resource. If we do not provide an implementation then the job is left to the finalizer and we already know this is bad. One thing we can do is implement the Disposable pattern and this will be correct but unnecessarily complicated solution. It will even result in some unnecessary work if we fallback to the finalizer since there will be one more object (the repository object) on the finalization queue. The correct way to do it is simply:

public void Dispose()
{
   connection.Dispose();
   //call Dispose() on all objects that implement IDisposable
}

That is right – all we need to do is call the Dispose method of all IDisposable objects owned by our class. Why is this enough? Well the IDisposable objects already implement the Disposable pattern so they will be put on the finalization queue anyway. No need to send them there via our object. Note that this is only correct if your object does not own any unmanaged resources directly. If it does then we are back to the full implementation.


   There are two downsides to this method that I am aware of:

- If another class derives from an IDisposable class built this way and the new class contains additional unmanaged resources then it is not easy for the derived class to dispose them. I have never encountered the need for this in practice so in most cases you just declare the class sealed but if you do need it or if you are implementing a library you may use this method which is still shorter than the full pattern (it does not have a destructor):

public void Dispose()
{
   Dispose(true);
   GC.SupressFinalize(this); //we need to call SupressFinalize since the derived class may need it
}

protected virtual void Dispose(bool disposing)
{
   if(disposing)
   {
       connection.Dispose();
   }
}

Which can be overriden in the derived class

protected override void Dispose(bool disposing)
{
   if(disposing)
   {
       additionalResource.Dispose();
   }
   base.Dispose();
}

The class has the option to add a finalizer as well if it holds an unmanaged resource directly.

- It is considered a good practice to throw an ObjectDisposedException for every method call if the object is disposed. I have never seen anyone do this in non-library code even when they implemented the Disposable pattern correctly. I guess we are all lazy. Still you may just add a flag indicating if the object has been disposed and check it in every method call.

   So this is what no popular article mentions - If you have an object that owns IDisposable objects you do need to implement the IDisposable interface but you do not need to implement the full Disposable pattern.

   Thanks to Jonathan Allen, Nikolay Pavlov and Ivelin Ivanov for assisting with the editing of this article.
Tags:   english programming 
Posted by:   Stilgar
23:02 14.01.2015

Comments:



No comments yet.




Post as:



Post a comment: