views:

66

answers:

4

I have this class:

class Foo : IDisposable
{
  SomeBigResource resource;

  void UsingResource()
  {
    using(Bar bar = new Bar(SomeBigResource)
      bar.doStuff();
  }

  void Dispose()
  {
    resource.Dispose();
  }
}

void Function()
{
  using (Foo foo = new Foo(new SomeBigResource))
    foo.UsingResource();
}

The Bar object has exactly the same Dispose() function.
Will my SomeBigResource be released or is the GC smart enough to release it later on when the second using is done?

+2  A: 

Your resource will be disposed twice.

The GC is completely unaware of IDisposables and the using statement.

Each using statement translates into a try / finally block with a Dispose() call in the finally block.
This is a normal method call which will always execute.

Therefore, the inner using statement in UsingResource() will dispose the resource, and then the outer using statement in Function() will dispose it again.

All IDisposable implementations should be idempotent (calling it a second time should do no harm). Therefore, (assuming that SomeBigResource implements IDisposable correctly), your code should work fine.

Note, though, that with your class, an empty using block will throw a NullReferenceException, which is very wrong.
You should add a null check in your Dispose method.

SLaks
So basically I should remove the using in UsingResource()?
the_drow
Actually, you should remove the field and make it a private variable.
SLaks
@the_drow, I would wrap the `using` around your instance of `SomeBigResource`, not the objects that are dependant upon that instance. `Foo` and `Bar` should not be responsible for cleaning up `SomeBigResource` if they did not create it.
Anthony Pegram
+2  A: 

This depends on the implementation of Bar.Dispose(). Assuming it has a similar implementation as Foo, then, yes, the release will occur early.

Take a look at the Dispose pattern guidance and this SO question. There are more corner cases than you may think of immediately.

Pontus Gagge
+2  A: 

I assume this line should read:

using(Bar bar = new Bar(resource))

If that's the case, then when bar is disposed, it should dispose of resource.

So, yes. When bar is disposed in UsingResource, it will dispose resource, so that if you attempt to use it later, it should throw an ObjectDisposedException. (Although in your simple example, that shouldn't happen.)

Toby
+4  A: 

If both the Dispose methods in Foo and Bar calls Dispose on the SomeBigResource object, the method will be called twice. If the method is implemented correctly it will release the resources the first time and do nothing the second time.

What you have is a confusion of responsibility, where both objects take responsibility for calling Dispose on the SomeBigResource object. This is something that you want to avoid, as one object can't know if the other object still needs the resource, so you want to put the responsibility in one place only.

You should either make the Foo object responsible for the life cycle of the resource, or handle it outside of the objects completely. The latter makes more sense, as that's where you create the SomeBigResource instance:

using (SomeBigResource resource = new SomeBigResource()) {
  using (Foo foo = new Foo(resource)) {
    foo.UsingResource();
  }
}
Guffa