views:

53

answers:

5

Let's say I've got a MyObject object that has two interfaces: IMyContract and IDisposable. And I have this code in a method:

IMyContract blah = new MyObject();
blah.Blah();
return;

This is a potential memory leak, right? Doesn't it need to be:

using (MyObject blah = new MyObject())
{
    blah.Blah();
}
return;
+5  A: 

Well, if it implements IDisposable you should indeed dispose it. There's no saying what will leak if you don't - or for how long - but you should have a using statement to avoid it anyway.

(Just to clarify: memory is the least likely thing to be leaked, as IDisposable is generally about unmanaged resources such as network connections etc. It's possible, of course - the object could have a handle on some memory allocated far away from the GC's gaze. Any implementation of IDisposable which holds direct references to unmanaged resources should also have a finalizer, so the leak should only be temporary... but that could still be painful.)

Jon Skeet
Doesn't the default Object.Finalize() inspect the instance to see if it's an IDisposable, and call the Dispose() method?
KeithS
@KeithS: "Object.Finalize does nothing by default." http://msdn.microsoft.com/en-us/library/system.object.finalize(VS.71).aspx Note that in C# you use the destructor syntax (`~ClassName()`) to override `Object.Finalize()`
Nelson
+1  A: 

you could call dispose in your first example as well:

IMyContract blah = new MyObject();
blah.Blah();
((IDisposable)blah).Dispose();
return;

not quite as clean, but sometimes you must use interfaces.

The other possibility is for your Interface to itself inherit IDisposable. Then you could use:

using (IMyContract blah = new MyObject())
{
    blah.Blah();
}
return;
Zippit
Note that if `Blah` throws an exception, you won't get to the `Dispose` line in the first case.
Jon Skeet
A: 

If IDisposable is implemented properly (with a finalizer that calls Dispose() and no SuppressFinalize), the Garbage Collector will get to it eventually. However, using() is the same as try { ... } finally { object.Dispose(); }, which will deterministically (explicitly, as soon as possible) dispose. If you depend on the Garbage Collector you may be surprised how long it takes to dispose. If there are unmanaged resources, you could quickly run out of them because they haven't been deallocated.

Edit: I missed the point of this the first time around. Yes, when you use MyObject you should Dispose() properly with using(). If you have other code that uses that interface then you could have something like:

public IMyContract GetInterface()
{
  using (MyObject obj = new MyObject())
  {
    obj.DoSomething();
    return (IMyContract)obj;
  }
}

The rest of the code can then use IMyContract contract = GetInterface(); without having to worry about (or even knowing) that things should dispose.

Nelson
I don't know if you meant to, but your answer implies that calling `object.Dispose` will deterministically deallocate memory. That's not the case at all. Calling `Dispose` deterministically releases any unmanaged objects that the object uses (provided, of course, that the `Dispose` method is implemented correctly), but it does not affect the garbage collected heap.
Jim Mischel
No, you're right. The GC will call the finalizer (if it's not suppressed), which following the standard `IDisposable` pattern would call `Dispose(true)` so that unmanaged resources are released.
Nelson
A: 

IDisposable has more been introduced to release the resources asap than to prevent leaks

It's still possible to leak even when implementing it and a class that does not implement it can be 100% leak free

vc 74
A: 

Technically, you cannot cause a memory leak. However, you may end up holding resources open longer than necessary.

If implementors of IMyContract normally are disposable (or likely could be disposable), then IMyContract should inherit from IDisposable. Otherwise, you could just have MyObject inherit from IDisposable.

Either way, the object should certainly be disposed.

Stephen Cleary