I understand that it is used to deallocate unmanaged resources, however, I am confused as to when Dispose
is actually called. I know it is called at the end of a using
block, but does it also get invoked when the object is garbage collected?
views:
422answers:
5Dispose() is called at the end of the Using block so that you can count on the Dispose actions (e.g. closing a db connection) to take place as the object goes out of scope. Simple as that.
Update: there is nothing specific to unmanaged resources in a call to Dispose (although that is a common use).
Update 2: there is a bit of a debate on the thread that Reed Copsey started that is useful for understanding IDisposable. I highly recommend this article for people wanting to know more.
In a nutshell, an IDisposable class allows you to explicitly handle the deallocation of resources (typically unmanaged resources or database connections) via the Dispose() method. IDisposable class instances should be created within a "Using" block so as to ensure that the Dispose method is actually called. If you fail to do this (or to call it explicitly in a "finally" block, etc.) then your Dispose method will not be called and you'll orphan the objects you'd like to clean up. In all cases, I place Disposable classes in Using blocks and you should too.
As an alternative you can handle the clean up of resources in a Finalizer (a class Destructor). This will be called automatically when the class is GC'd. The disadvantages of this approach are that you will not explicitly control when objects are cleaned up and there are some threading issues to contend with. Thus, for example, problems in Destructors are very difficult to debug due to the fact that they are called asynchronously and in a different thread. The only advantage is that you don't have to remember to call your Destructor like you do Dispose. Of course, if you always use Using blocks, this is a non-issue.
NOTE: I ktrauberman, Reed and Pontus have made some good points about how you can get around the points I make below. This is what I do, but I cannot argue that this is the only way to do things. Indeed, Microsoft even recommends calling Dispose() from your Finalizer in some instances. However, I'll leave the discussion here just as an illustration of why it is important to follow Reed's advice re: being careful when mixing Destructors and Dispose().
Where I disagree with the Reed's answer is in the assertion that you should implement an IDisposable class by calling Dispose() within your Finalizer. This just conflates the two different constructs and may well lead to problems. For example, if you do create your IDisposable class instance in a Using block and you call Dispose() in the Destructor, it will be called twice - with potentially nasty and difficult to debug crashes (again - you don't control the timing of GC). (Side note: this is actually true of Destructors in general - they can, in certain circumstances be called more than once!)
Dispose is called in a few places:
- At the end of a using block.
- When explicitly called (in a try{} finally{} for instance.)
It is recommended that you call it yourself when you are done with a resource, to better manage resources.
EDIT: I was mistaken. Dispose is NOT called during garbage collection. See this article.
See this previous question: Proper use of the IDisposable interface
No it does not get called when the object is garbage collected. If you want that behavior you can use the destructor (finalizer) and the call Dispose()
from there.
As you say it is automatically called and the end of a using
block.
If you implement IDisposable correctly, you should also include a finalizer that will call Dispose() on your object.
If you do that, it will get called by the GC. However, it's still a VERY good idea to try to always dispose of these objects yourself.
The biggest problem with relying on the finalizer to call Dispose is that it will happen in another thread which you don't control. This can have nasty consequences in certain situations, including causing an exception that's happening in the GC thread, which is not good, as well as having a disposed field you check. This is also part of why including GC.SuppressFinalize(this) in your Dispose() method is important - once an object's disposed, you don't want to re-dispose it.