Should IDisposable.Dispose() implementations be idempotent?
Asked Answered
F

4

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?

Fetal answered 19/1, 2012 at 9:42 Comment(0)
D
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).

Dumont answered 19/1, 2012 at 9:45 Comment(7)
Just because Microsoft doesn't always follow their own recommendation doesn't mean you should.Bladdernut
@Bladdernut - Can you please expand on your rather cryptic comment?Dumont
I wonder if he's referring to WinForms throwing an exception if you Dispose a Control twice.Cnut
@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?Fetal
@IvayloSlavov - Whenever you have shared state across threads... But you really should ask a new question for that.Dumont
Thanks again, will certainly do.Fetal
Like Dave said, I'm talking about winforms handle deallocation in particular and handle deallocation in general which is error prone.Bladdernut
C
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
     {
         // ...
     }

}
Caylor answered 19/1, 2012 at 9:48 Comment(5)
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.Devaughn
@R.MartinhoFernandes - yes but it is still something to add :)Caylor
@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.Fetal
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.Devaughn
@R.MartinhoFernandes - Note to self: never try to explain something in one line if two lines are better.Caylor
V
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.

Vancouver answered 19/1, 2012 at 9:46 Comment(1)
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. "Cleres
E
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.

Endoergic answered 19/1, 2012 at 9:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.