Thursday, June 21, 2007

When Dispose() isn't enough

A while back I had a discussion with another developer on my current project about Dispose() and the need to call an object's Close()/Stop()/etc methods before calling Dispose(). I was of the opinion that classes implementing IDisposable would be smart enough to do whatever cleanup was necessary without the caller needing to also call Close() or Stop() or whatever other method "disables" that object's functionality. He argued that you may not always be able to rely on Dispose() being implemented properly. I came back with the System.Data.SqlClient.SqlConnection object and showed in Reflector that it does indeed call Close() during Dispose(bool). See, I'm right!

Well, today I had to eat my words and agree with him (You were right Dave! :-) ). We use WMI even notifications to raise scheduled events by subscribing to changes on Win32_LocalTime. While trying to diagnose why we sometimes get a "Quota Violation" exception when subscribing I opened up Reflector to look at the ManagementEventWatcher class. The ManagementEventWatcher has a Stop() method which disables event notifications. The bad part is that it inherits from System.Component.ComponentModel (which implements IDisposable) but does not override Dispose(bool). This results in leaking event subscriptions when a Start()'d ManagementEventWatcher is Disposed without first calling Stop().

So, lesson learned... unless you know for sure (ie. you've checked using Reflector), always call the "disabling" method (Stop(), Close(), whatever) before Disposing your IDisposable objects. In a perfect world any object implementing IDisposable would correctly clean up after itself, but in the real world that's not the case!

No comments: