Should Idisposable.Dispose() Be Made Safe to Call Multiple Times

Should IDisposable.Dispose() be made safe to call multiple times?

You should be safe to call it more than once, though you should probably avoid it if you can.

From the MSDN page on IDisposable.Dispose():

If an object's Dispose method is called more than once, the object must ignore all calls after the first one. The object must not throw an exception if its Dispose method is called multiple times.

Are IDisposable objects meant to be created and disposed just once?

@Jon Skeet has answered the question really well, but let me chip in with a comment that I feel should be an answer by its own.

It is quite common to use the using code block to temporarily acquire some resource, or enter some form of scoped code you want a clean exit from. I do that all the time, in particular in my business logic controllers, where I have a system that postpones change-events until a block of code has executed, to avoid side-effects multiple times, or before I'm ready for them, etc.

In order to make the code look more obvious to the programmer that uses it, you should look at using a temporary value that you use instead of the object that has the resource, and returning it from a method name that tells the programmer what it is doing, ie. acquiring some resources temporarily.

Let me show an example.

Instead of this:

using (node) { ... }

you do this:

using (node.ResourceScope()) { ... }

Thus, you're not actually disposing of anything more than once, since ResourceScope will return a new value you dispose of, and the underlying node will be left as is.

Here's an example implementation (unverified, typing from memory):

public class Node
{
private Resource _Resource;

public void AcquireResource()
{
if (_Resource == null)
_Resource = InternalAcquireResource();
}

public void ReleaseResource()
{
if (_Resource != null)
{
InternalReleaseResource();
_Resource = null;
}
}

public ResourceScopeValue ResourceScope()
{
if (_Resource == null)
return new ResourceScopeValue(this);
else
return new ResourceScopeValue(null);
}

public struct ResourceScopeValue : IDisposable
{
private Node _Node;

internal ResourceScopeValue(Node node)
{
_Node = node;
if (node != null)
node.AcquireResource();
}

public void Dispose()
{
Node node = _Node;
_Node = null;
if (node != null)
node.ReleaseResource();
}
}
}

This allows you to do this:

Node node = ...
using (node.ResourceScope()) // first call, acquire resource
{
CallSomeMethod(node);
} // and release it here

...
private void CallSomeMethod(Node node)
{
using (node.ResourceScope()) // due to the code, resources will not be 2x acquired
{
} // nor released here
}

The fact that I return a struct, and not IDisposable means that you won't get boxing overhead, instead the public .Dispose method will just be called on exit from the using-block.

What is the resulting behavior when an IDisposable is passed into a parent IDisposable

is it correct to assume that the object X will take ownership of Y and from that point onwards, calling X.dispose() will always result in calling Y.dispose()

No, it is never save to assume that. Let's check this specific case: XmlReader.Create(Stream).

After going to quite some code in the Reference Source, I have found that the Dispose method calls the Close method. That is quite obvious. Then notice this piece of code:

public override void Close() {
Close( closeInput );
}

So whether the backing stream will be closed and disposed depends on the value of the setting closeInput, which you can set through the XmlReaderSettings.CloseInput setting.

So the answer here is a definite no: you can't be sure it is disposed. You should always make sure yourself it is.

IDisposable and private bool disposed. How it works?

The GC will only ever release the memory of an object when it is sure that none of it's instance members will ever be invoked by code again. So while the quote is correct that it's possible for the object to have been collected before Dispose finishes executing, that's only true if there is no possible code path from where the currently executing code is that would ever reach an instance variable. So in your particular implementation, it wouldn't be able to free the memory for the object until after this.disposed = true; had already run (assuming there's no other possible means of any executable code to ever access another instance variable).

So the whole point of that assertion is to tell you that you either need to be okay with the instance being cleared before the cleanup is finished, or you need to access some instance member (which it does by setting disposed) after any operations that would expect the instance to still exist.

That said, these points are all generally rather esoteric and pretty rarely come up. If you are never accessing any instance members you're unlikely to even realize that the object's memory was technically freed before some other unmanged disposal was finished. If you were actively trying to observe the effect, you'd probably have to use something like weak references or unsafe code holding a reference to some of that instance state (which is exactly why you should avoid doing things like that whenever possible).

Do i need to Dispose Stream when i Pass it to IDisposable class?

Yes, you can write code like that.

But, no, you should not do that.

Your class looks like on of XxxxReader classes that by convention own the stream they read from. As result your MyFileReader class is expected to dispose the inner stream. You also normally expected to dispose each and every disposable object when you know that such object's lifetime is over.

Note that sometimes it lead to multiple Dispose calls on some objects (which should be expected by implementations of IDisposable). While it may sometimes lead to Code Analysis warning it is better than missing Dispose calls if one routinely tries to "optimize" number of calls to Dispose by skipping some.

Alternative approach is to expose method that reads content which by convention is not expected to take ownership of stream/reader like:

 using(stream....)
{
var result = MyFileReader.ReadFrom(stream);
}

Will the Garbage Collector call IDisposable.Dispose for me?

The .Net Garbage Collector calls the Object.Finalize method of an object on garbage collection. By default this does nothing and must be overidden if you want to free additional resources.

Dispose is NOT automatically called and must be explicity called if resources are to be released, such as within a 'using' or 'try finally' block

see http://msdn.microsoft.com/en-us/library/system.object.finalize.aspx for more information

IDisposable with destructor: requires thread-safe implementation?

While it is sometimes possible for an object to be finalized while a seemingly-live reference exists, that can only happen when nothing else is going to ever refer to the object. The GC.SuppressFinalize(this) actively refers to the present object 'this', thus guaranteeing that it will not be finalized until the GC.SuppressFinalize executes. Further, the fact that the object reference existed to dispose the object, and was available to the Dispose method, guarantees that the finalizer couldn't have been queued before Dispose started running unless the object was dead and a finalizer somewhere (either its own finalizer, or that of some other object) resurrected it.

Because there are some scenarios where an object could be scheduled for finalization and resurrected without ever being aware of it, it may not be a bad idea to protect a dispose and finalize against redundant operation. Microsoft's pattern is not a good one, however. Finalizable objects shouldn't hold references to any objects not needed for finalization. If an object would hold a mixture of managed and unmanaged resources, the unmanaged resources should be moved into their own classes (effectively turning them into managed resources), so then the main object would hold nothing but managed resources.



Related Topics



Leave a reply



Submit