views:

631

answers:

7

I'm trying to make sure that my understanding of IDisposable is correct and there's something I'm still not quite sure on.

IDisposable seems to serve two purpose.

  1. To provide a convention to "shut down" a managed object on demand.
  2. To provide a convention to free "unmanaged resources" held by a managed object.

My confusion comes from identifying which scenarios have "unmanaged resources" in play.

Say you are using a Microsoft-supplied IDisposable-implementing (managed) class (say, database or socket-related).

  1. How do you know whether it is implementing IDisposable for just 1 or 1&2 above?
  2. Are you responsible for making sure that unmanaged resources it may or may not hold internally are freed? Should you be adding a finalizer (would that be the right mechanism?) to your own class that calls instanceOfMsSuppliedClass.Dispose()?
A: 

Yes, you're responsible to call the Dispose method - or better use using statement. If an object is implementing IDisposable, you should always dispose it, no matter what.

using (var myObj = new Whatever())
{
   // ..
}

is similar to

{
  var myObj;
  try
  {
     myObj = new Whatever();
     // ..
  } 
  finally
  {
    if (myObj != null)
    {
      ((IDisposable)myObj).Dispose();
    }
  }
} // object scope ends here

EDIT: Added try/finally thanks to Talljoe - wow, that's complicated to get it right :)

EDIT2: I am not saying that you should use the second variant. I just wanted to show that "using" is nice syntactic sugar for a bunch of code that can get quite messy and hard to get right.

VVS
Actually, it's similar to:Whatever myObj;try { myObj = new Whatever(); /* .. */ }finally { if(myObj != null) ((IDisposable)myObj).Dispose;
Talljoe
@Talljoe- that's right a lot of people forget the myObj != null check.
RichardOD
Is Dispose() ALWAYS required? I always thought in the case of things like a FileStream, doing a FileStream.Close() and allowing the garbage collector to collect it wouldn't result in any issues. Dispose/Using would be better, i'd agree, but wouldn't this still be okay?
Will Eddins
@Guard: Maybe, maybe not. And even if it's ok now, the implementation might change in future versions of the framework. If you ensure that you always dispose of any IDisposable objects then you don't need to worry about their underlying implementation, or any future changes to it.
LukeH
This code won't compile, because when you get to the "finally", myObj might be uninitialized. E.g., if "new Whatever()" threw an exception, then myObj never would have been assigned. Typically you would put the assignment just *before* the start of the "try" block. Then you don't need the null check. Alternatively, you could choose not to reinvent the wheel, and just use the "using" keyword -- that's what it's there for.
Joe White
@Joe: Actually my point IS that you should use the "using" statement. I tried to show what "using" is internally and not how to do it the hard way.
VVS
+5  A: 

You should always call Dispose on objects that implement IDisposable (unless they specifically tell you' it's a helpful convention, like ASP.NET MVC's HtmlHelper.BeginForm). You can use the "using" statement to make this easy. If you hang on to a reference of an IDisposable in your class as a member field then you should implement IDisposable using the Disposable Pattern to clean up those members. If you run a static-analysis tool like FxCop it will tell you the same.

You shouldn't be trying to second-guess the interface. Today that class might not use an unmanaged resource but what about the next version?

Talljoe
I always use FXCop to check I have called Dispose, and nearly always do it with a using statement.
RichardOD
+10  A: 
  1. How do you know whether it is implementing IDisposable for just 1 or 1&2 above?

The answer to your first question is "you shouldn't need to know". If you're using third party code, then you are its mercy to some point - you'd have to trust that it's disposing of itself properly when you call Dispose on it. If you're unsure or you think there's a bug, you could always try using Reflector() to disassemble it (if possible) and check out what it's doing.

  1. Am I responsible for making sure that unmanaged resources it may or may not hold internally are freed? Should I be adding a finalizer (would that be the right mechanism?) to my own class that calls instanceOfMsSuppliedClass.Dispose()?

You should rarely, if ever, need to implement a finalizer for your classes if you're using .Net 2.0 or above. Finalizers add overhead to your class, and usually provide no more functionality then you'd need with just implementing Dispose. I would highly recommend visiting this article for a good overview on disposing properly. In your case, you would want to call instanceofMSSuppliedClass.Dispose() in your own Dispose() method.

Ultimately, calling Dispose() on an object is good practice, because it explictly lets the GC know that you're done with the resource and allows the user the ability to clean it up immediately, and indirectly documents the code by letting other programmers know that the object is done with the resources at that point. But even if you forget to call it explicitly, it will happen eventually when the object is unrooted (.Net is a managed platform after all). Finalizers should only be implemented if your object has unmanaged resources that will need implicit cleanup (i.e. there is a chance the consumer can forget to clean it up, and that this will be problematic).

womp
"Ultimately, calling Dispose() .. allows the user the ability to clean it up immediately ... But even if you forget, it will happen eventually when the object is unrooted."That's the info I was really after. So, if the author of the class that's holding the ACTUAL unmanaged resources implements the IDisposable+Finalizer pattern properly, the cleanup will always happen some way or another in the end.
frou
Correct! And as a side note, if you ever did have to write a finalizer, you should only ever be finalizing objects that your object owns directly. Finalizing other object's resources can lead to all kinds of nasty.
womp
That linked article calling `Dispose` a destructor syntax... dunno... I prefer this one: http://nitoprograms.blogspot.com/2009/08/how-to-implement-idisposable-and.html and the dirty details in http://www.codeproject.com/KB/dotnet/idisposable.aspx
romkyns
+1  A: 

You're not responsible for the contents of an object. Dispose() should be transparent, and free what it needs to free. After that, you're not responsible for it.

Unmanaged resources are resources like you would create in (managed) C++, where you allocate memory through pointers and "new" statements, rather than "gcnew" statements. When you're creating a class in C++, you're responsible for deleting this memory, since it is native memory, or unmanaged, and the garbage collector does not about it. You can also create this unmanaged memory through Marshal allocations, and, i'd assume, unsafe code.

When using Managed C++, you don't have to manually implement the IDisposable class either. When you write your deconstructor, it will be compiled to a Dispose() function.

Will Eddins
A: 

Why should it matter to you?

When possible I wrap the scope of a disposable object in a using. This calls dispose at the end of the using. When not I explicitly call dispose whenever I no longer need the object.

Whether for reason 1 or reason 2 is not necessary.

Jeroen Huinink
+1  A: 

If the class in question is Microsoft-supplied (ie.. database, etc..) then the handling of Dispose (from IDisposable) will most likely already be taken care of, it is just up to you to call it. For instance, standard practice using a database would look like:

//...
using (IDataReader dataRead = new DataReaderObject())
{
   //Call database
}

This is essentially the same as writing:

IDataReader dataRead = null;
try
{
    dataRead = new DataReaderObject()
    //Call database
}
finally
{
    if(dataRead != null)
    {
        dataRead.Dispose();
    }
}

From what I understand, it is generally good practice for you use the former on objects that inherit from IDisposable since it will ensure proper freeing of resources.

As for using IDisposable yourself, the implementation is up to you. Once you inherit from it you should ensure the method contains the code needed to dispose of any DB connections you may have manually created, freeing of resources that may remain or prevent the object from being destroyed, or just cleaning up large resource pools (like images). This also includes unmanaged resources, for instance, code marked inside an "unsafe" block is essentially unmanaged code that can allow for direct memory manipulation, something that definitely needs cleaning up.

Zensar
Well I also didn't scope my IDataReader object correctly either, it was kinda meant as a quick description of the "using" statement. I will edit my post so as not to confuse people, or worse, risk having them write something that way, thanks!
Zensar
Still won't compile; see my notes on VVS's answer. You should be instantiating immediately before the start of the "try" block. Or use "using".
Joe White
The point of the code is a generalized description of what the using statement is doing. The code isn't meant to be utilized, mainly because using is the accepted method. But you are right, the code won't compile, the dataRead object should be set as NULL before it is initialized. There is a reasoning behind initializing the object inside the try statement though. The using statement will wrap the object in a try, because the object may have a complex initialization that throws an exception. The using statement would handle these and finish with a pass to finally.
Zensar
A: 

One piece that is missing here is the finalizer - my habit has been if I implement IDisposable I also have a finalizer to call Dispose() just in case my client doesn't. Yes, it adds overhead but if Dispose() IS called than the GC.SuppressFinalize(this) call eliminates it.

n8wrl
What does your Dispose do? If all you're doing is calling Dispose on other objects, then adding your own finalizer is a waste of effort and runtime. The objects that actually hold onto unmanaged resources (sockets, file handles, GDI+ handles, window handles, etc.) will almost certainly have finalizers already, and will clean themselves up if they're GCed without being Disposed first. You don't need to add extra overhead (and code complexity) to do what would have happened anyway.
Joe White
MSDN is pretty explicit on the IDisposable pattern, to include a finalizer. I don't think 'almost certainly' is good enough, so I think a finalizer with IDisposable is important.
n8wrl
This is the discussion my awkwardly worded question was trying to get at. The distinction between IDisposable classes that ACTUALLY hold unmanaged resources, and IDisposable classes that just have other IDisposable instances as members.
frou
Call me dense, but I just don't see the difference. If I write a class that uses disposable objects, I'm going to implement IDisposable, with a finalizer, to make sure it's cleaned up. I don't think I should be thinking about whether the objects I'm using 'really' dispose something or not, just like MY callers shouldn't be making that determination about my class. IDisposable is a contract and its meaning is clear.
n8wrl
@n8wrl: well you should be thinking about that unfortunately. You should NOT call other classes' Dispose when disposing via the finalizer. Look at the MS patter _carefully_ - if you implement the pattern properly then your class will do NOTHING when Dispose gets called from the finalizer, because of that "if (disposing)" thing.
romkyns