23

The Microsoft.NET framework provides the IDisposable interface which requires an implementation of void Dispose() method. Its purpose is to enable manual, or scope-based releasing of expensive resources an IDisposable implementation may have allocated. Examples include database collections, streams and handles.

My question is, should the implementation of the Dispose() method be idempotent - when called more than once on the same instance, the instance to be 'disposed of' only once, and subsequent calls not to throw exceptions. In Java, most of the objects that have similar behavior (again streams and database connections come to my mind as examples) are idempotent for their close() operation, which happens to be the analogue for the Dispose() method.

However, my personal experience with .NET (and Windows Forms in particular), shows that not all implementations (that are part of the .NET framework itself) are idempotent, so that subsequent calls to these throw an ObjectDisposedException. This really confuses me on how a disposable object's implementation should be approached. Is there a common answer for the scenario, or is it dependent on the concrete context of the object and its usage?

Ry-
  • 218,210
  • 55
  • 464
  • 476
Ivaylo Slavov
  • 8,839
  • 12
  • 65
  • 108

4 Answers4

20

should the implementation of the Dispose() method be idempotent

Yes, it should. There is no telling how many times it will be called.

From Implementing a Dispose Method on MSDN:

a Dispose method should be callable multiple times without throwing an exception.

An object with a good implementation of IDispose will have a boolean field flag indicating if it has been disposed of already and on subsequent calls do nothing (as it was already disposed).

Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • 7
    Just because Microsoft doesn't always follow their own recommendation doesn't mean you should. – linkerro Jan 19 '12 at 10:09
  • @linkerro - Can you please expand on your rather cryptic comment? – Oded Jan 19 '12 at 10:14
  • I wonder if he's referring to WinForms throwing an exception if you Dispose a Control twice. – DaveShaw Jan 19 '12 at 11:15
  • @DaveShaw, that's the reason I asked this question. Oded, thanks for the answer, it confirmed my belief that idempotent dispose logic is essential. Still, I another question arises - when should synchronization mechanisms be applied too? – Ivaylo Slavov Jan 19 '12 at 12:15
  • @IvayloSlavov - Whenever you have shared state across threads... But you really should ask a new question for that. – Oded Jan 19 '12 at 13:33
  • Thanks again, will certainly do. – Ivaylo Slavov Jan 19 '12 at 13:57
  • Like Dave said, I'm talking about winforms handle deallocation in particular and handle deallocation in general which is error prone. – linkerro Jan 20 '12 at 07:20
7

Yes, also make sure the other methods of the class respond correctly when they are called when the object has already been disposed.

public void SomeMethod()
{
     if(_disposed)
     {
         throw new ObjectDisposedException();
     }
     else
     {
         // ...
     }

}
Emond
  • 50,210
  • 11
  • 84
  • 115
  • Being able to cope here may be to simply throw an exception. And I'm not really sure if anything should be required at all. Please don't require disposed objects to still "work" in some way. Trying to use a disposed object is a bug and should be treated as such. – R. Martinho Fernandes Jan 19 '12 at 09:51
  • @R.MartinhoFernandes - yes but it is still something to add :) – Emond Jan 19 '12 at 09:52
  • @R.MartinhoFernandes, I think what @Emo is saying is - if you still posses a reference to an already disposed object, and call some of the other methods it has, these methods should throw the `ObjectDisposedException`, or otherwise notify the caller that the operation is illegal at for this state. Unfortunately, I believe this might come at a prize of sinchronization awareness. – Ivaylo Slavov Jan 19 '12 at 09:55
  • 1
    I agree that throwing a boneheaded exception (using Eric Lippert's taxonomy) is the right thing to do. And now that the answer makes this clearer, I even +1ed. As it was before it could be misinterpreted to mean something else. – R. Martinho Fernandes Jan 19 '12 at 10:00
  • 1
    @R.MartinhoFernandes - Note to self: never try to explain something in one line if two lines are better. – Emond Jan 19 '12 at 10:02
4

From MSDN:

Allow a Dispose method to be called more than once without throwing an exception. The method should do nothing after the first call.

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • 3
    You maybe should have included the next point for clarity: "Throw an ObjectDisposedException from instance methods on this type (other than Dispose) when resources are already disposed. This rule does not apply to the Dispose method because it should be callable multiple times without throwing an exception. " – Jamiec Jan 19 '12 at 09:57
4

Personally - Yes - I always make Dispose() idempotent.

During the usual life-cyle of an object in a given application it may not be necessary - the life-cyle from creation to disposal may be deterministic and well known.

However, equally, in some applications it might not be so clear.

For example, in a decorator scenario: I may have a disposable object A, decorated by another disposable object B. I may want to explicitly dispose A, and yet Dispose on B may also dispose the instance it wraps (think: streams).

Given it is relatively easy to make Dispose idempotent (ie if already disposed, do nothing), it seems silly not to.

Rob Levine
  • 40,328
  • 13
  • 85
  • 111