blog.jj5.net (2003 to 2005)

Always calling dispose (Part II of an endless series)

Mon Oct 4 15:18:00 UTC+1100 2004

Categories:

You see. This is the whining bullshit that I'm talking about. And I didn't even say anything in this thread.

Here's another tome I was compelled to write, but that I won't be posting.

John.

--

Ryan Heath wrote:
> Lets put the record straight for all the .net programmers out there
> (and for ourselfs)

OK: IDisposable is broken.

> - There is no diff between Close and Dispose (if implemented correctly)

Incorrect.

> other than that after a Dispose, the object is not usable for other actions

That's one difference. What about the fact that Dispose is optional and Close is probably not? What about that Dispose can be called any number of times but Close probably not? What about that Dispose can't throw exceptions (the stupidest thing I ever heard of; what if there's an exception?) but Close probably can?

> - use (whenever appropriate)

What constitutes appropriate? This is like telling someone 'obey the law' and then not telling them what the law is.

> - don't use Dispose/Close when you do not control the objects lifetime

What is 'Close'? You mean Stream.Close()? SqlConnection.Close()? Door.Close()?

Close is a 'word'. It doesn't mean anything to this discussion without specific context. I assume when you say Dispose you mean IDisposable.Dispose, which is definitely different to SqlConnection.Close() which in turn is different to Stream.Close() and almost certainly different to Door.Close().

> I think thats about it...

If only that were so.

> Anyone more suggestions to add to this list?

- IDisposable is an interface with a single method, Dispose, that you can *optionally* call when you are finished with an object to affect immediate release of its unmanaged resources. If you don't call Dispose then these unmanaged resources will be released in a finaliser.

- Close is the name of a method that you will find on many interfaces, typically with a matching Open() method. A common pattern is that if you call Open() once you must guarantee to call Close() once.

- Doing more in IDisposable.Dispose than releasing unmanaged resources and invalidating the instance undermines the usefulness of the interface, because developers can not be sure of how to treat it when there is a question mark over ownership or scope. Developers who come to rely on the 'extended' contract may have a problem in the future. Developers who are forced to rely on the 'extended' contract will be furious.

- Having 'using' target the IDisposable undermines its usefulness as a C# language integration feature for use as a scoping tool. Because in order to maintain the integrity of the IDisposable interface nothing other than the release of unmanaged resources should be done with it. Thus making 'using' useless in a purely managed environment.

- IDisposable is tightly integrated to the .NET component model, forcing tight ownership.

- IComponent defines a Disposed event that seems to somehow be related to the optional IDisposable.Dispose method.

- Sometimes specs claim 'Dispose' is called but IDisposable.Dispose isn't called. For example, there are situations where ControlCollection.Dispose() is called directly rather than IDisposable.Dispose(). ControlCollection.Dispose() and IDisposable.Dispose() on ControlCollection are not the same thing! If ControlCollection.Dispose does the same thing as the IDisposable.Dispose method on ControlCollection then if ControlCollection is not sealed then it should be implemented like this:

public class ControlCollection : ..., IDisposable {

  void IDisposable.Dispose() {

    // release unmanaged resources
    // suppress finalization

  }

  ~ControlCollection() {

    // release unmanaged resources

  }

  public void Dispose() {

    ((IDisposable)this).Dispose();

  }
}

- Interfaces should be implemented *on the interface* for all but sealed classes.

- IDisposable started life as a hack for deterministic finalisation but tried to grow in its scope, and failed.

- IComponent declares IDisposable even though many IComponent objects do not own unmanaged resources.

- Some classes in the BCL implement IDisposable.Dispose but do more than release unmanaged resources. As a result you have to question whether you should or should not be calling Dispose on any given instance.

- IDisposable is only suitable or useful for strong ownership situations. The entire point of the GC is that you don't need to worry about strong ownership. That is, IDisposable goes a long way to undermining the facility in GC, particularly because of its poor specification and implementation. You really can't expect anyone to call Dispose in a managed environment where 'sharing resources' is supposed to be trouble free.

- IDisposable sucks and blows at the same time!

John.


Copyright © 2003-2005 John Elliot