Here are two classes that allocate resources, the first class needs to implement a custom destructor and standard Dispose, but the second class doesn't need either.
The difference is that the first class allocates resources in the constructor and doesn't clean them up immediately. In contrast, the second class allocates resources in a member function and carefully frees them before exiting (using a finally block), so the second class author doesn't need to bother writing Dispose and a destructor.
class MustDispose
{
public MustDispose()
{
create a 3rd party object
open a file handle
allocate some memory
open a database connection
open a network port
}
~MustDispose()
{
// customized destructor for this class
if (3rd party object != null) free the 3rd party object
if (file handle != null) close the file handle
if (memory != null) free the memory
if (connection != null) close the database connection
if (port open) close the network port
}
public void Dispose()
{
// because this class needs a destructor, it also needs this
// idiomatic Dispose method
Finalize();
System.GC.SuppressFinalize(this);
}
}
class NoDispose
{
public NoDispose()
{
// this class has an uninteresting constructor so it doesn't need
// a destructor or Dispose
}
MemberFuncThatCleansUp()
{
try
{
create a 3rd party object
open a file handle
allocate some memory
open a database connection
open a network port
}
finally
{
if (3rd party object != null) free the 3rd party object
if (file handle != null) close the file handle
if (memory != null) free the memory
if (connection != null) close the database connection
if (port open) close the network port
}
}
}
If a class needs a destructor, you should customize how it is written. However, the Dispose method has become an idiom in C# for any class that needs a destructor:
public
void Dispose()
{
Finalize();
System.GC.SuppressFinalize(this);
}
When to Call Dispose
Call Dispose on an object you create if the class author provides Dispose.
Call Dispose as soon as you are done using an object, especially if the object will remain in scope during a lengthy operation or if the object allocates significant resources of its own. If the object you create doesn't itself allocate significant resources (but how do you know that?) then it might not be a problem to simply let the object go out of scope and have C# call its destructor automatically.
Finally, here's a C# tip to actually avoid calling Dispose:
MustDispose obj =
new MustDispose;
try
{
// use the object
}
finally
{
if (obj != null)
((IDisposable)obj).Dispose();
}
You can shorten this up and just write this instead:
using (MustDispose obj = new MustDispose)
{
// use the object
}
This assumes that exceptions will be caught at a higher level, which is usually recommended. In other words, don't catch just to throw.