.NET GC Best Practice -- ALWAYS Call Dispose

Its very common practice to not call Dispose on a lot of .NET objects, like DataSets or SqlCommands for instance.  There's even been several discussion on these blogs about the best practices in some of these cases.  The problem is that many of us “know” that calling Dispose on some objects actually does nothing underneath -- it simply exists due to an inheritance chain that included the IDisposable interface.  So many experts (myself included) have gotten in the habit of writing the most “efficient” code, which often means the fewest lines necessary.  So why call Dispose if we know it does not do anything?  As my colleague Doug Ware pointed out to me, this assumes some internal knowledge that should not be relied upon and which technically could even change in the future.  Instead, we should remember that the IDisposable pattern was implemented for a reason in general, and so we should follow it or risk being in error at some point.  In other words, what's the harm in writing this extra line of code that “might” have significant reasons for existing.

18 Comments

  • An elegant means of inoking Dispose that have adopted is using the "using" construct. For those of you who may not nbe familiar with the construct, it provide a means to implicity invoke Dispose() on an instance that implements IDisposable even if an exception is thrown durring the operation. The following is an example of the using construct:



    using(DisposableClass dc = new DisposableClass())

    {

    dc.PerformActionOnUmanagedResources();

    dc.PerformAnotherActionOnUmanagedResources();

    }

    In the previous example, if an exception was thrown in the PerformActionOnUmanagedResources() method, although the PerformAnotherActionOnUmanagedResources() method would not be processed, the using block will still implicity invoke the Dispose method on dc ensuring the realese of any unmanaged resources.

  • The Using keyword will also be added to VB.NET in .NET v2.0.

  • Isn't it just easier to use unmanaged C++ if you need control over releasing resources? I thought the whole selling point of managed environment was that you don't have to do that...

  • Also, remember on things like a SqlConnection you may not want to call Dispose because it actually closes the connection while the Close method does not if connection pooling is on. So you would see performance loss if you disposed the connection because a new connection really would have to be opend and thus connection pooling would be a waste.

  • Sorry Adam, but I disagree. First, I've looked at the source code in Anakrino, and all Dispose does is call Close and null out the connection string -- nothing more. I've also tried this for myself, and I didn't see that behavior. Maybe this is another myth that is making the rounds, but there's nothing like trying it for yourself.

  • But Paul, you didn't write the most important thing. Why should we explicitly call the Dispose method? It is still being called by the GC, so why call it manually? Is there any performance gain, can you point to some whitepaper saying this?



    Thanks,



    Radim

  • Hi Radim:



    Why should you explicity call Dispose? First, because it is NOT automatically called by the GC! That seems to be a very common misunderstanding. The only way to automate the call to Dispose is if you using the C# using keyword. Otherwise, objects that implement IDisposable must have their Dispose method called manually -- it will NOT be called by the GC. That said, the typical implementation pattern, but not guaranteed, is that the same code that frees the unmanaged resources in the Dispose method will also be executed in the Finalizer method. The problem with this, which is itself a big assumption, is that in order for Finalizers to be executed they have the side-effect that such objects don't get GCed very quickly at all. Instead, when the object would have gotten GCed it instead gets Finalized and then promoted to the next heap generation. It will then only get GCed when that next heap generation is actually GCed, which could be quite a bit delayed since that's the point of heap generations. By the way, the proper implementation pattern for the Dispose method is that the code in that method should also call GC.SuppressFinalization to turn off the Finalizer and avoid the usual GC delay that Finalizers incur. So if you are not calling Dispose manually, or using the C# using keywork, then you are relying on the Finalizer, which will always incur a large cost, and you are also making an assumption that there is a Finalizer and that it does the same thing as Dispose.



    Dispose is your friend, and its there for a reason -- call it when it exists!



    Thanks, Paul Wilson

  • I'm swore I read somewhere on msdn that calling Close() will call Dispose().

    Which kind of makes sense for the idioms we see. Open() the connection, Close() the connection. I've seen no idioms where Dispose() is called instead in this case.

    Let me know if you think this is correct or not. If not I'll try to locate the source that I read it from.

  • Decompiling it shows that Dispose calls Close -- Close does not call Dispose, although the effect is the same. However, the point I'm making is that the only way you can say its safe to not call Dispose is because you have some inside knowledge, either from an expert or from a decompiler. But internal implementations can change, and its a very bad practice to ignore the very pattern, IDisposable, that was included for a reason just because you think its safe to ignore it. Trust me, I've code this way too, and I don't like adding an extra line when I don't think I need to do so, but its these types of assumptions that have proven to be wrong in many cases, even if not in this case. Thus my advice is to trust the pattern, not the assumptions of insider information.

  • Paul,

    I cracked open SqlDataReader in ildasm and you're correct, Dispose() calls Close().

    However, I opened up the TextWriter and in this case Close() calls Dispose().

    Is there a "theory for everything" reason for this? Or are different developers at MS implementing their own interpretations of patterns?

    Thanks.

  • SqlConnection.Close() puts the connection back to the pool. You can reopen it later by using Open().

    If you use SqlConnection.Dispose() it releases the ConnectionString, so you CAN'T open it again. That's the main difference.

  • The IDisposable pattern has left it open for class library designers whether to have an alternately named method or simply have Dispose. If the design warrants a domain-specific method name (i.e. Close for streams), the intent than is to explicitly implement the interface so that not both Dispose and Close are available when viewed as the object's type. If casted to IDisposable, than Dispose becomes available.



    In the case of the SqlConnection class, the designers did not follow that guideline, but made both Close and Dispose available with slight differences in behavior. Although, I recognize the goal was to allow reopening the connection, it has actually led to far more confusion than reaping the benefits, IMO. Add to it that earlier MSDN documentations incorrectly stated that Dispose did not return the connection to the pool, it has been difficult to get developers to switch to the using/IDisposable temporary resource pattern with connections.

  • Nice discussion but no one have mentioned the ASP.NET control´s Dispose method. And I´m curious on that issue because many controls have the Dispose and what we harldy see is them being called in the code behind.

  • If my class uses just private variables( no other resources and unmanaged code) like:

    Class Test
    {

    #region Fields
    private int test1;
    #endregion

    #region Properties
    public int Test1{ get; set; }
    #endregion

    }

    Do I need to implement Dispose method for this class?

    Thanks in advance...

  • No, you don't need a Dispose method unless you have something else, like a file or stream or db connection, that needs Disposing.

  • Thanks for your reply. I am using Microsoft Enterprise Library and one of my method in DAL looks like:

    Database db = DatabaseFactory.CreateDatabase();

    DbCommand myCommand = db.GetStoredProcCommand("MySPName");

    Do I need Dispose for db(Database Connection) and myCommand(Db Command)?

    Also when I use SMTP object to send mail, Do I need to call Dispose Method?

    In short, can you please tell me the type of the objects that require Dispose()?

    Thanks in advance...

  • So what is the verdict on calling dispose on connections then? Because if you don't call it for database connectiosn then basically the only time you actually need to call it is when using a fileStream or TextStream basically right? So in 99% of your .net code you will never call dispose correct?

  • Database connections definitely need to be closed or disposed (close calls dispose). You can use a try / finally block, with close or dispose in the finally block, or use a "using" block, which translates to the try / finally block in the il without all the work for you.

    What other objects should have dispose called? In general any object that implements IDisposable should use try / finally or "using" to make sure dispose gets called. There are certainly some cases where we may be "smart" enough to know it doesn't matter, but you may be wrong, and it may change in the next version, so don't be too "smart"!

Comments have been disabled for this content.