Consider this:
interface IFoo : IDisposable { }
class Program
{
static void Main()
{
var foo = GetFoo();
var anotherFoo = foo;
using(anotherFoo)
{
}
// Will the object on the heap be marked for collection?
// Or will this confuse the garbage collector
// as we are copying references?
}
}
That raises the more important question. What does Dispose()
actually do?
Dispose
method is added in consideration of the fact that resources other than managed memory (unmanaged resources) still need to be released explicitly; GC was specifically not design for it.
Moreover, the mechanism behind IDisposable
is independent of the GC. When you follow the Dispose Pattern, you may optionally plug in your code into GC by making your class finalizable, but you do not have to do that as part of implementing IDisposable
.
Disposing is related to cleaning up the hidden resources the object holds, not the "shell" of the object inside managed memory. Very often an object would throw ObjectDisposedException
on attempts to use it after the call of Dispose
.
Going back to your code, since the two variables actually refer to the same object, the foo
variable would be referencing a disposed object after the using
block. Therefore, calling methods or accessing properties of foo
after using
may raise an exception:
var foo = GetFoo();
var anotherFoo = foo;
using(anotherFoo)
{
}
foo.doSomethingUseful(); // <<== This may throw ObjectDisposedException!
"Copying a reference" as you describe does not do anything to the original object. It's just another way of looking up the same object via a different name -- like if you have a separate email address the mail of which always gets addressed to your mailbox. Either way you get to the same object. Thus if you dispose one then you dispose the other.
When you have the code:
using (anotherFoo)
{
}
You are using the using
syntax to ensure that the last thing that happens before the block finishes is that the .Dispose
method on the object referenced by the variable anotherFoo
will be disposed. Thus it is exactly the same as if you had done using (foo) { ... }
.
Edit Responding to Comment:
First, and most importantly, IDisposable
has nothing to do with garbage collection. That happens on its own. In this example, since both foo
and anotherFoo
are local variables and not (apparently) being escaped from the method via closures, method calls, etc, they will be GC'ed almost as soon as the method call finishes.
IDisposable
, on the other hand, is intended purely to allow you to free (generally) external resources such as OS handles like files, UI primitives, sockets, etc. While it's true that you definitely want the object to dispose of it's resources when it's GC'ed, without IDisposable
you can't control the inverse -- IDisposable
allows you to clean up resources at the very moment when it is not being used anymore. This allows you to engineer more deterministic solutions to problems that deal with external resources -- more than relying purely on what the GC would allow.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With