Reputation: 4104
I've been trying to increase my understanding of garbage collection, managed & unmanaged resources, and "proper design principles" regarding memory management as I am interested in getting into "lower level" programming and things of that nature.
I understand that you're supposed to use using
block or some other solution for ensuring these unmanaged resources do in fact get disposed, but I don't understand what is happening under the hood.
I was looking at this article: Implementing a Dispose Method on MSDN and was confused by this particular line:
To help ensure that resources are always cleaned up appropriately, a Dispose method should be callable multiple times without throwing an exception.
Lets look at the example code they provide for the dispose pattern:
class DerivedClass : BaseClass
{
// Flag: Has Dispose already been called?
bool disposed = false;
// Instantiate a SafeHandle instance.
SafeHandle handle = new SafeFileHandle(IntPtr.Zero, true);
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
handle.Dispose();
// Free any other managed objects here.
}
// Free any unmanaged objects here.
disposed = true;
// Call base class implementation.
base.Dispose(disposing);
}
}
I believe what the quoted text above is basically saying is, "We added a bool disposed
property so that we can check if that's true
and return
if so. If it's false
then we dispose of the actual resources. That way we don't actually dispose of something multiple times"
But this didn't make sense to me. If we've gotten rid of an object, how can you call Dispose
on it a second time?
To investigate, I wrote a console application containing the following 3 lines:
var cmd = new SqlCommand();
cmd.Dispose();
cmd.Dispose();
This compiles and executes without problem -- which makes sense, given the quoted text from the article. But I don't understand what's actually happening.
I set a breakpoint and stepped over each line. After the first Dispose
is called, I expected the Locals window in Visual Studio to tell me that cmd
is null
. And following this train of thought I asked myself, "How can you call Dispose
on null
?" Obviously, you can't. So what is happening? Why is cmd
still a SqlCommand
object after its been disposed of the first time?
What exactly does Dispose
do, and if I've disposed of my object why does it seem to still exist for all intents and purposes?
Why / How does the following compile and run without problem?
var cmd = new SqlCommand();
cmd.Dispose();
cmd.CommandText = "I figured this would throw an exception but it doesn't";
Upvotes: 0
Views: 974
Reputation: 361
The IDisposable
interface is being called by several consuming classes and - as already stated by Dark Falcon - when you encapsulate the usage of your class in a using block. This makes it easier to keep your unmanaged resources clean.
But Dispose
is just like any other method and not to be confused with destructors/finalizers (which is what you apparently expected it to be)
Upvotes: 2
Reputation: 44201
There is nothing special about Dispose
except for the fact that a using
statement can call it for you. Other than that, it is just like any other .NET function. It does not magically set any variables to null
, cause exceptions to be thrown if the object is used again, or anything like that.
Likewise, IDisposable
is not a special interface in any way except that objects in a using
statement must implement it. You could consider a using statement to be something like this:
// using(var a = somethingDisposable()) {otherCode();}
var a = somethingDisposable();
try
{
otherCode();
}
finally
{
if(a != null)
((IDisposable)a).Dispose();
}
Upvotes: 1