I was having a discussion with a colleague recently about the value of Dispose
and types that implement IDisposable
.
I think there is value
everything ultimately is an unmanaged resource.
Not true. Everything except memory used by CLR objects which is managed (allocated and freed) only by the framework.
Implementing IDisposable
and calling Dispose
on an object that does not hold on to any unmanaged resources (directly or indirectly via dependent objects) is pointless. It does not make freeing that object deterministic because you can't directly free object's CLR memory on your own as it is always only GC
that does that. Object being a reference type because value types, when used directly at a method level, are allocated/freed by stack operations.
Now, everyone claims to be right in their answers. Let me prove mine. According to documentation:
Object.Finalize Method allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection.
In other words object's CLR memory is released just after Object.Finalize()
is called. [note: it is possible to explicitly skip this call if needed]
Here is a disposable class with no unmanaged resources:
internal class Class1 : IDisposable
{
public Class1()
{
Console.WriteLine("Construct");
}
public void Dispose()
{
Console.WriteLine("Dispose");
}
~Class1()
{
Console.WriteLine("Destruct");
}
}
Note that destructor implicitly calls every Finalize
in the inheritance chain down to Object.Finalize()
And here is the Main
method of a console app:
static void Main(string[] args)
{
for (int i = 0; i < 10; i++)
{
Class1 obj = new Class1();
obj.Dispose();
}
Console.ReadKey();
}
If calling Dispose
was a way to free a managed object in a deterministic way, every "Dispose" would be immediately followed by a "Destruct", right? See for yourself what happens. It is most interesting to run this app from a command line window.
Note: There is a way to force GC
to collect all objects which are pending finalization in the current app domain but no for a single specific object. Nevertheless you do not need to call Dispose
to have an object in the finalization queue. It is strongly discouraged to force collection as it will likely hurt overall application performance.
EDIT
There is one exception - state management. Dispose
can handle state change if your object happens to manage an outside state. Even if state is not an unmanaged object it is very convenient to use it like one because of special treatment IDisposable
has. Example would be a security context or impersonation context.
using (WindowsImpersonationContext context = SomeUserIdentity.Impersonate()))
{
// do something as SomeUser
}
// back to your user
It is not the best example because WindowsImpersonationContext
uses system handle internally but you get the picture.
Bottom line is that when implementing IDisposable
you need to have (or plan to have) something meaningful to do in the Dispose
method. Otherwise it's just a waste of time. IDisposable
does not change how your object is managed by GC.