Note: See also the sequel IDisposable Reloaded…
IDisposable is one of these beasts. Considered to be common knowledge and yet I regularly encounter code that simply ignores the demand. A well documented pattern and yet I occasionally stumble over improper usage of the pattern. And this is just the beginning; the finer details are lost more often than not.
Calling IDisposable
IDisposable’s sole purpose is to free scarce or expensive resources quickly and cleanly. The usually mentioned examples are files, database connections, and unmanaged resources. Rarely mentioned is the fact that a class becomes an expensive resource by the very fact that it implements IDisposable (and asuming the pattern below is used, including the finalizer. If Dispose() is not called the object will survive one garbage collection, making it to the second generation and live longer than intended, blocking memory and requiring a more thorough GC to get freed.)
Therefore the advice is: If it implements IDisposable, call it. Always!
Basic implementation
Implementing IDisposable is a well documented pattern but it regularly is not observed properly. The gist is:
- Implement IDisposable.Dispose() to call a protected virtual method Dispose(bool disposing) with true and deregister the object from finalization (i.e. call GC.SuppressFinalize(this);)
- Implement the finalizer to call Dispose(false) as fallback, should the caller forget the call to IDisposable.
- Implement Dispose(bool) to free managed resources if disposing is true and to always free unmanaged resources.
public class DisposableObject: IDisposable
{
~DisposableObject()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// free managed resources
}
// free unmanaged resources
}
}
If you implement IDisposable you have to follow this pattern. Period. And you do implement it if your class manages other resources, e.g. if it holds a file reference or some kind of unmanaged handle.
OK, up to here we’ve covered what I should hope to be common knowledge. But there is more. Not terribly complicated but things to consider anyway.
Advanced patterns
One decision to be made is how the object will behave after disposing it.
- It could be revived, e.g. a file could be reopened. In this case it should GC.ReRegisterForFinalize(); to start all over.
- The call could be oblivious, i.e. not care at all but also not providing the means to do anything with it (e.g. providing the necessary calls only as c’tors).
- It could be unforgiving; in which case it would throw an ObjectDisposedException.
Please note that the following classes build on the above example (i.e. DisposableObject).
Revivable object:
public class RevivableObject : DisposableObject
{
public RevivableObject()
{
// not yet…
GC.SuppressFinalize(this);
}
public void Open(/*…*/)
{
// open the resource
// and make sure the GC knows about this
GC.ReRegisterForFinalize(this);
}
}
Oblivious object:
public class UseOnlyOnceObject : DisposableObject
{
public UseOnlyOnceObject(/*…*/)
{
// open the resource only via c’tor
}
}
Guarded object: Every method needs to call AssertNotDisposed() as precondition.
public class GuardedObject : DisposableObject
{
bool _disposed = false;
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_disposed = true;
}
protected void AssertNotDisposed()
{
if (_disposed)
throw new ObjectDisposedException(GetType().FullName);
}
void Foo()
{
// check preconditions
AssertNotDisposed();
// …
}
}
Dispose and tell
A fair number of classes do not only dispose themselves, they also tell about it — via a respective event (e.g. the component class.)
public class ObservableObject : DisposableObject
{
public event EventHandler Disposed;
protected virtual void OnDisposed(EventArgs ea)
{
if (Disposed != null)
Disposed(this, ea);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
OnDisposed(EventArgs.Empty);
}
}
Object graphs
Consider the following use case: You implement some kind of controller pattern for your web pages; the controller manages references to business services. A simple implementation would look like this:
public interface IBusinessService
{
}public class Controller
{
Dictionary<string, IBusinessService> _services= new Dictionary<string,IBusinessService>();
public IBusinessService GetBusinessService(string name)
{
IBusinessService ret= null;
_services.TryGetValue(name, out ret);
if (ret == null)
{
ret = CreateBusinessService(name);
_services[name] = ret;
}
return ret;
}
protected virtual IBusinessService CreateBusinessService(string name)
{
// create business service, e.g. using a factory
return null;
}
}public class PageWithController: Page
{
Controller _controller;
public Controller Controller
{
get { return _controller; }
}
protected override void OnPreInit(EventArgs e)
{
_controller = CreateController();
base.OnPreInit(e);
}
protected virtual Controller CreateController()
{
// create controller , e.g. using a factory
return new Controller();
}
}
Now, what does that have to do with IDisposable? No disposable object is taking part in this sample, right?
However this implementation lays the infrastructure to be used with derived classes, controllers as well as business services. And those derived classes may very well implement IDisposable, e.g. a business service holding a database reference. Should the implementor of that business service have to build the disposing infrastructure for that service? Or should the infrastructure anticipate that need and already be aware of IDisposable? Take that as rhetorical question and have a look at the corrections:
public class Controller: GuardedObject
{
// code as above…
protected override void Dispose(bool disposing)
{
if (disposing)
{
DisposeHelper.DisposeElements(_services.Values);
_services = null;
}
base.Dispose(disposing);
}
}public class PageWithController: Page
{
// code as above…
public override void Dispose()
{
DisposeHelper.Dispose(_controller);
_controller = null;
base.Dispose();
}
}
I leave the implementation of the DisposeHelper class to your imagination.
So, the advice in this case is: If you for lay some kind of basic infrastructure, anticipate the usage of disposable objects and build an uninterrupted “dispose trail”.
“””If you implement IDisposable you have to follow this pattern. Period.”””
I disagree. You only have to follow this pattern if you have unmanaged resources, and I suspect that the majority of IDisposable classes that people write don’t have unmanaged resources.
Comment by Aaron — May 30, 2007 @ 4:08 am
Quote: If Dispose() is not called it will survive one garbage collection.
That’s not true. You are confusing classes with a finalizer with those that implement IDisposable. While it is common that an IDisposable class _usually_ has a finalizer defined, that’s not part of the IDisposable interface, just (good) convention. Of course, just having someone call the Dispose method doesn’t _prevent_ the finalizer unless the author was good enough to remember the call to GC.SupressFinalize(this) in it.
I know this seems like pendantry, but you have to understand the pattern to apply it correctly and loose descriptions like the one quoted are misleading.
Comment by Marc Brooks — May 30, 2007 @ 8:13 am
@Marc: You’re right, that was a little lax. I corrected the phrase.
Comment by ajdotnet — May 30, 2007 @ 9:57 am
What about implementing IDisposable to delete some temp files uploaded to the web server. You can’t realy control when a user leaves in a web app scenario. There’s no opened file handle here, there’re just some temp files uploaded that would be deleted when your object is GCed. Can you comment on this? Thanks!
Comment by Adi — May 31, 2007 @ 4:39 am
@Aaron: What do you mean? Implement IDisposable and do _not_ follow the pattern if it’s about managed resources? Well, it’s surely not the only pattern. But then, it’s feasible, it covers the ground, and it definitly is the (Microsoft) recommended way to do it.
And following this pattern is not only about handling resources correctly. Patterns in general are also about readability, doing the same things the same way, not confusing people by doing similar things differently, … . The Page class does not follow this pattern (seems Microsoft could not herd the cattle), and it always stands out for that very reason.
Comment by ajdotnet — May 31, 2007 @ 7:28 am
@Adi: If I understand correctly, the life time of your temp files should be similar to the time the user is your web site? In that case, using the GC to maintain the life time wouldn’t work anyway. Since the GC might run at any time, independently of requests and “active users”, the files might not even survive one request.
I would try to imlepement something similar to caching. Touch the files if they are accessed and have a job run in the backgound that regularly deletes files older than, say 20 min. A simple commandline application registered with the scheduler would do.
Comment by ajdotnet — May 31, 2007 @ 7:38 am
Hi there
Great article. I want your input on this particular case I have.
I have a class (A) that holds a reference to another class (B). Class B then subscribes to an event published by another class (C). At some point, class A might not need class B any more, and class B should be GC’ed. However, since class B has subscribed to class C event, it’s not GC’ed.
So, if I write a basic implementation of the IDisposable pattern (like you propose in your blog post here), class A would simply call class B’s dispose method when it is no longer needs class B. The dispose method in class B would then unsubscribe to class C’s event, and then call GC.SuppressFinalize(this).
But, should I call GC.SuppressFinalize(this)?
Class B has a few other managed resources besides the event hook, managed resources like List objects and other objects that class B uses. Are those automatically set to null or do I also have to set those to null manually if I call GC.SuppressFinalize(this)?
Would it, in that case, be better just to unsubscribe to class C’s event in the Displose method and then NOT call GC.SuppressFinalize(this) – having the GC do it’s magic as it would do normally.
Comment by Egil Hansen — July 1, 2007 @ 6:44 pm
@Egil: I asume that C is still around when you dispose B (otherwise you won’t have to deal with deregistering the event at all). And yes, you should call GC.SuppressFinalize(this) in Dispose(). One reason is simply “the pattern says so” :-). It’s part of the beauty of patterns that you don’t have to think about these things anymore, just do it and go on the important stuff. The technical reason is simply the the next GC will collect B if you do; if you didn’t call the method, B would linger around for another GC, making it to the next generation.
Regarding the other resources: They are not set to null automatically but you don’t have to do that manually either. Since they are not reachable by a living object, the GC will collect them anyway. Personally I set members to null only after I explicitly disposed them (just as a safety measure). Anyway, the call to GC.SuppressFinalize(this) will not affect any of those objects, i.e. one had a finalizer, it would still be called.
You could of course refrain from using the pattern at all; a simple Unsubscribe() method called instead of Dispose() might be sufficient in your case. In this case you don’t have to bother with a finalizer and GC.SuppressFinalize(this) at all. After all, the primary purpose for finalizers is dealing with unmanaged resources (if only referenced indirectly).
Comment by ajdotnet — July 2, 2007 @ 8:44 am
[…] https://ajdotnet.wordpress.com/2007/05/28/idisposable-1-2-3/ […]
Pingback by IDisposable - 1,2,3 … « All about nothing — August 23, 2007 @ 3:07 pm
[…] As third improvement I re-worked all classes that implements the IDisposable interface in order to use the correct IDisposable Pattern. […]
Pingback by AdFactum ObjectMapper .NET Blog » Blog Archive » New Release - AdFactum ObjectMapper .NET 1.90.1917.0 — September 17, 2007 @ 9:20 pm
here my situation – I have a class – let’s call it A. This class implements IDisposable and within the dispose method I have implemented gc.suppressfinalize(this). Class A holds reference to collection of Objects. This collection is essentially class B. Again, I have implemented IDisposable Interface and within the dispose method I have implemented gc.suppressfinalize(this). Is this the right way of implementing things or am i missing something?
Comment by Mohan — January 19, 2008 @ 4:12 am
Mohan, your class A should actually call B.Dispose() in its own Dispose(bool) method. Apart from that clarification this looks perfectly well.
AJ.NET
Comment by ajdotnet — January 19, 2008 @ 10:29 pm
AJ.NET: I will go ahead and make the change in my code, however, would there have been any negative performance impact between the way I earlier implemented the IDisposable interface vs. not implementing the IDisposable interface at all. thanks, Mohan
Comment by Mohan — January 20, 2008 @ 12:08 am
Also, as per comment 12: should I simple iterate thru the collection in A class Dispose(bool) method calling b.dispose – here what i mean.
class A
{
private List _ListofB;
}
Comment by Mohan — January 21, 2008 @ 10:18 pm
Also, as per comment 12: should I simple iterate thru the collection in A class Dispose(bool) method calling b.dispose – here what i mean.
class A:IDisposable
{
private List _ListofB;
public void Dispose()
{
Dispose(true);
System.GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
foreach (CartItem c in CartItemList)
{
c.Dispose();
}
}
}
}
Sorry abt comment 14. I pressed Submit Comment inadvertently, and thanks for the help
Comment by Mohan — January 21, 2008 @ 10:21 pm
I read you initial use case in #11 as if the list class itself implemented IDisposable, but if that is not the case your code in #15 is essentially correct.
Once you have to do that more often, you may welcome a set of (simple enough) helper methods:
[DebuggerStepThrough]
public static void Dispose(IDisposable id)
{
if (id != null)
{
id.Dispose();
}
}
[DebuggerStepThrough]
public static void Dispose(object o)
{
IDisposable disposable = o as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
public static void Dispose<T>(ref T o)
{
IDisposable disposable = o as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
o = default(T);
}
[DebuggerStepThrough]
public static void DisposeElements(IEnumerable enumerable)
{
if (enumerable != null)
{
IEnumerator enumerator = enumerable.GetEnumerator();
while (enumerator.MoveNext())
{
Dispose(enumerator.Current);
}
}
}
With this your Dispose(bool) method would look like this:
protected virtual void Dispose(bool disposing)
{
if (disposing)
MyHelper.DisposeElements(_ListofB);
}
HIH, AJ.NET
Comment by ajdotnet — January 22, 2008 @ 8:05 am