# Tuesday, May 20, 2008

This is another one in the series "heck, I never thought of that"... Like most of these articles, if you already knew this trick, ignore me...

Let's say you have a generic class with a new() constraint on the type parameter. This means that you are allowed to create new objects of the generic type, like this:

class GenericClass<T> where T:new()
{   
   public void SomeMethod()   
   {      
      T obj = new T();
      ...
   }
}


Pretty straightforward stuff, BUT there is a possibility that type T implements IDisposable, meaning that you should clean up after using any object of type T (using the Dispose method or a "using" block.

The trivial way of solving this problem is:

class GenericClass<T> where T:new()
{
   public void SomeMethod()
   {
      T obj = new T();

      ...

      if (obj is IDisposable)
         ((IDisposable) obj).Dispose();
   }
}

 

Not too bad, but we can do better:

class GenericClass<T> where T:new()
{
   public void SomeMethod()
   {
      T obj = new T();

      using (obj as IDisposable)
      {
         ...
      }
   }
}


Pretty neat, don't you think? What actually happens is that the using block creates a "hidden" variable of type "IDisposable" and will call Dispose() on it when exiting the scope of the using block. If T does not implement IDisposable, the hidden variable will be null, and the compiler will not try to call Dispose().

kick it on DotNetKicks.com
Tuesday, May 20, 2008 11:29:08 PM (W. Europe Daylight Time, UTC+02:00)  #    Comments [5] -

Wednesday, May 21, 2008 11:03:02 AM (W. Europe Daylight Time, UTC+02:00)
Or you can add IDisposable as a constraint on your class:

class GenericClass<T> where T: IDisposable, new()
{
public void SomeMethod()
{
using(T obj = new T())
{
...
}
}
}
Wednesday, May 21, 2008 11:38:59 AM (W. Europe Daylight Time, UTC+02:00)
Of course you could do that, but then the class is restricted to types that implement IDisposable.

The code presented allows any type to be used, and if it implements IDisposable, it will use the dispose pattern to clean it up after using it.
Wednesday, May 21, 2008 2:48:15 PM (W. Europe Daylight Time, UTC+02:00)
This smells a little. I believe that the point of the IDisposable pattern is to illustrate who is in control of the clean-up of the object. There should be no ambiguity.

Your class is either in control of disposing things or not and burying it inside a method like this is, IMHO, non-obvious and going to be unexpected to would-be callers.

I would strongly suggest that you defer the creation-of and disposal-of the object to your caller, or else make it more explicit by having two different methods, one that handles IDisposable and one that doesn't or something to that effect.

Just out of curiosity, what situation involves you 'new()'-ing up objects? Perhaps that's the problem and there might be a different, better way for handling this situation that doesn't involve this compromise.

I've often found that when I get to a situation like this where I have to make a choice between two bad decisions, I've made a mistake somewhere else higher up the chain
Wednesday, May 21, 2008 3:01:21 PM (W. Europe Daylight Time, UTC+02:00)
In this case the generic class itself is in control of the creation of the object. It's true that creating objects of a generic type in a generic class isn't common practice, but it does happen, otherwise C# wouldn't provide the "new()" constraint.

So, in case the class wants to create objects of that type, it should also clean up disposable objects appropriately using Dispose(). This post merely presents a clean and efficient way of doing just that.
Wednesday, May 21, 2008 8:21:53 PM (W. Europe Daylight Time, UTC+02:00)
Nice trick.

Note that you should never use the first sample, because if an exception is thrown while code "..." executes, obj will not get disposed.

A using block actually behaves like a try-finally, so the second sample is fine. Another solution is to wrap "..." with a try block and attempt to dispose in a finally block.
Comments are closed.