It's hard to find at design/compile time types that are IDisposable but that are not disposed correctly. What methods are there at runtime to find them?
views:
43answers:
2It is good practice to implement IDisposable
if your type is resource hungry, but, this is just good practice and cannot be enforced by the compiler.
One thing you can do to make abusing IDisposable
s more noticeable, is to make them throw
or assert
in the finalizer
(remember, if your type is disposed properly, the finalizer won't get called because you'll have called GC.SuppressFinalize
in your dispose method). The following program shows an error in the debugger's output window when the app finishes because Hog
is not correctly disposed.
class Program
{
static void Main(string[] args)
{
new Hog( ) ;
}
}
class Hog : IDisposable
{
public void Dispose( )
{
Dispose( true ) ;
GC.SuppressFinalize( this ) ;
}
protected virtual void Dispose( bool disposing )
{
GC.SuppressFinalize( this );
}
~Hog( )
{
Debug.Fail( @"You didn't dispose me!" ) ;
Dispose( false ) ;
}
}
You'll see the following error in the debugger:
---- DEBUG ASSERTION FAILED ----
---- Assert Short Message ----
You didn't dispose me!
---- Assert Long Message ----
at Hog.Finalize()
but, if you did use the disposable object correctly, such as:
static void Main(string[] args)
{
using (new Hog())
;
}
...you won't see anything.
To make things even more useful, you can record the current stack trace in the constructor and dump it out in the destructor. So the new, more useful Hog
would look like:
class Hog : IDisposable
{
readonly StackTrace _stackTrace ;
public Hog( )
{
#if DEBUG
_stackTrace = new StackTrace();
#endif
}
public void Dispose( )
{
Dispose( true ) ;
GC.SuppressFinalize( this ) ;
}
protected virtual void Dispose( bool disposing )
{
GC.SuppressFinalize( this );
}
~Hog( )
{
#if DEBUG
Debug.WriteLine("FinalizableObject was not disposed" + _stackTrace.ToString());
#endif
Dispose( false ) ;
}
}
and using it (without disposing it) would give you this in the debugger output window:
FinalizableObject was not disposed at ConsoleApplication1.Hog..ctor()
at ConsoleApplication1.Program.Main(String[] args)
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
Code analysis tools like FxCop (included in Team Editions of Visual Studio or as a free download) can detect this.
Though there will be occasional false negatives/positives.