3

Firstly, sorry if this is considered a duplicate - I know it is a common topic, but I have looked and not found a satisfactory answer.

There are a lot of questions asking when to use IDisposable, but from everything I've read, I just can't see why you wouldn't implement it in every class you make. What is there to lose? Does it have a big performance hit?

Part of my understanding of IDisposable is that one of the things it does is: Dispose()ing other IDisposables owned by the object. Forgive my ignorance, but does this apply only to fields/properties of the given object, or does it also extend to objects created within its methods too?

For instance, if a Font was created inside a method within a class that implements IDisposable, but that Font wasn't initialised with a using block, or .Dispose()d explicitly at the end of the method; would it be disposed when its IDisposable parent/class was GCd/disposed? Or otherwise, would the Font never be disposed?

I don't mean to digress, but if it is true that it would act as a 'catch all' like this (effectively disposing of any erroneous child IDisposable objects that would otherwise be left undisposed), isn't that reason alone enough to justify always implementing IDisposable whenever possible?

Community
  • 1
  • 1
Alfie
  • 2,341
  • 2
  • 28
  • 45
  • Well, yes. If you need to release resources.. follow the already established patterns. Implement `IDisposable`.. – Simon Whitehead Sep 06 '13 at 00:08
  • 1
    See this question which asks the opposite question. IDisposable should really only be implemented when you really need to (especially since it's non-obvious how to implement it correctly) http://stackoverflow.com/questions/1125693/general-rule-for-when-to-implement-idisposable – Robert Levy Sep 06 '13 at 00:10
  • Generally, I find it quite rare that I need to keep long lived IDisposable instances, especially with async/await, so implementing IDisposable for every instance would be major overkill. Not all classes are UI classes. – spender Sep 06 '13 at 00:10
  • Thanks for your comments all... @SimonWhitehead: While there is no doubting your logic, I'm afraid I find it doesn't really answer my question. – Alfie Sep 06 '13 at 00:20
  • @RobertLevy: That is actually one of the questions I read before posting, but I can't see where any of the points relate to your POV, please can you explain your thoughts? – Alfie Sep 06 '13 at 00:21
  • @spender: do you know how major the overkill would be? Even if it was sometimes used unnecessarily, might that not be balanced out by [some] potential 'memory leak fixes' that might otherwise be overlooked? – Alfie Sep 06 '13 at 00:22
  • 1
    @Alfie: If you lose a reference to an IDisposable object by creating a Font in a method without disposing, then there's nothing you can do about it. If the lost IDisposable is correctly implemented then GC's call to the finalizer should clean things up. – spender Sep 06 '13 at 00:34
  • Thanks @spender that answers one of my main queries, but I can't help wondering how you could end up with a correctly implemented but lost IDisposable :) – Alfie Sep 06 '13 at 00:41
  • @Alfie: Easy. Declare a variable in local scope without storing it in a field (or a property), at the end of the scope (e.g. the end of a method), you lose a reference to it. From now on, your code has no way of hitting the object. The last chance comes along when GC decides to collect the object and if a finalizer is implemented, it will call it (under most circumstances). You lose any control over when the finalizer code will run, which could probably be undesirable. – spender Sep 06 '13 at 00:50

3 Answers3

9

The rule is very simple, you need to implement IDisposable if you have any fields in your class that are of a type that is disposable. So that you can dispose them.

What happens inside a method has little to do with the fields of your class. If you create the font and store it in a field then yes, the above rule says that you need a Dispose() method. If you don't but just use the font to draw something, like you normally do, then always use the using statement so you immediately dispose the font after you are done using it.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Thanks @HansPassant, this was helpful. So I would be right to conclude that the `Dispose()` method of the containing class has no affect on variables created inside other methods (during the life of the class instance)? And a `Font` made without a `using` or `Dispose()` in this situation would just go MIA? – Alfie Sep 06 '13 at 00:35
  • You write the Dispose() method, nothing is auto-magic. And no, you cannot access the local variables of another method in your Dispose() method. Those variables have evaporated a long time ago. – Hans Passant Sep 06 '13 at 00:41
  • I thought that was the case - thanks for the confirmation. But doesn't implementing `IDisposable` mean it's children/disposable fields will automatically have their `Dispose()` called too, without having to explicitly call them all in the class' Dispose method? – Alfie Sep 06 '13 at 00:48
  • @Alfie: No, it doesn't. – spender Sep 06 '13 at 00:52
  • 3
    +1. Note that "have any fields" is somewhat wrong "have any fields and own objects" may be better. There are cases when object has a field which contains `IDisposable`, but the object does not *own* that `IDisposable`. In such case you must not dispose the `IDisposable` inside of your object (and likely should not implement `IDisposable` on that object). Sample could be wrapper class that packs parameters to a method (i.e. `{destinationName, stream}` as parameter to some `CopyTo` method). – Alexei Levenkov Sep 06 '13 at 01:10
  • @AlexeiLevenkov: I wish .NET had different types for things like "reference that encapsulates object ownership", "persistable reference that encapsulates identity but not ownership", "ephemeral reference that does not encapsulate ownership", etc. If the type system could accommodate that, then things like collections could more intelligently handle things like `Equals` and `GetHashCode`. – supercat Dec 03 '13 at 19:32
1

Most objects don't need it. The framework takes good care of Garbage Collection. COM objects and Graphics objects are among the ones that do and should implement IDisposable for good clean up. Yes there may be some inherent performance loss when recycling objects.

OneFineDay
  • 9,004
  • 3
  • 26
  • 37
0

An object should implement IDisposable if it will know of things that need to happen sometime before the end of the universe, and nothing else is going have the knowledge and impetus necessary to ensure that those things get done; the Dispose method lets the object know that it had better do those things immediately, because otherwise they'll likely never get done.

An abstract type or interface should implement IDisposable if it is likely that instances of a derived or implementing that type might know of things that need to happen sometime before the end of the universe, and the last entity holding a reference is apt to know that it's an instance of something derived from or implementing the abstract or interface type, rather than as something which implements a more specific type that implements IDisposable.

A type which implements an interface that inherits IDisposable will be required to implement IDisposable, whether or not it would have any other reason for doing so.

Types which have reason to implement IDisposable should do so. Types which don't, shouldn't.

ADDENDUM

To understand why one shouldn't always implement IDisposable, it may be helpful to consider the real cost of doing so. The amount of time required for the processor to call a do-nothing Dispose method is trivial, but that isn't the real consideration. The bigger issue comes when one considers that most objects fit one of four descriptions:

  • Objects which encapsulate resources, and need to have one clearly-defined owner

  • Objects which encapsulate mutable state, and need to have one clearly-defined owner.

  • Objects of immutable types, which do not need to have clearly-defined owners.

  • Instances of mutable types which will never be exposed to code that could mutate them, and do not need to have clearly-defined owners.

Correct use of mutable objects generally requires keeping track of who owns them, as is the case with objects that hold resources. Likewise, if an object with mutable state is used to encapsulate mutable state for another object, proper use of the latter object will require keeping track of who owns it, as is the case with objects encapsulating other objects that own resources. The difference is between objects with resources and those with mutable state is that when an instance of a mutable type is used to encapsulate the state of an immutable object (ensuring the instance is never exposed to code that would mutate it), it will no longer be necessary to keep track of who owns it. By contrast, it's necessary to track ownership of objects which encapsulate other objects that hold resources, even if those objects are semantically immutable.

supercat
  • 77,689
  • 9
  • 166
  • 211