Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using guidelines for generics and IDisposable

Tags:

c#

c#-4.0

In item 5 of More Effective C#, the following is presented:

public class EngineDriver<T> where T : IEngine, new()
{
  public void GetThingsDone()
  {
    T driver = new T();
    using (driver as IDisposable)
    {
      driver.DoWork();
    }
  }
}

The goal here is to properly dispose of drive, if it implements IDisposable. This makes sense, but how is this implementation different from the more succinct:

public class EngineDriver<T> where T : IEngine, new()
{
  public void GetThingsDone()
  {
    using (T driver = new T())
    {
      driver.DoWork();
    }
  }
}

Shouldn't the code above behave in exactly the same way? In fact, isn't the original code dangerous in that the lifetime of driver is beyond the using block, but driver is disposed of at the end of said block?

like image 418
Michael Goldshteyn Avatar asked Dec 02 '22 04:12

Michael Goldshteyn


2 Answers

No, because T does not necessarily implement IDisposable (unless IEngine itself implements it) - the second will not compile in this case, whereas the first will.

Regarding the scope of driver - it will still be accessible after the using block in the second example which is not ideal, and attempting to do so would usually result in an exception. Ideally you should have IEngine implement IDisposable or add an additional constraint to EngineDriver that T implement it.

like image 85
Lee Avatar answered Dec 14 '22 23:12

Lee


It is kinda important that you use the tools that are available to you. Compile your proposed code. I'll wait a few minutes.

Okay, you're back. Yes, you need to add a constraint for IDisposable so that the using statement is always capable of disposing the object. The code from the book is a hack around that restriction, it will work even if T does not implement IDisposable. using (null) {} is valid.

like image 29
Hans Passant Avatar answered Dec 14 '22 22:12

Hans Passant