共用方式為


Should Interfaces Derive from IDisposable?

I've been defining some interfaces for some classes in our code.  The classes implement IDisposable and I was wondering whether the class' corresponding interface should also derive from IDisposable.

For example:

class Foo : IFoo, IDisposable
{
    public void Bar() { }
    public void Dispose() { }
}

interface IFoo
{
    void Bar();
}

The question is: should IFoo derive from IDisposable?  My co-worker and I both decided that it should not.  Our reasoning was that the dispose implementation should only exist if the class required it.  Since the interface can have varying implementations, it is up to the class to define whether it implements IDisposable.  The IDisposable interface doesn't really contribute to contract of the interface; it's purely an implementation detail that should not be exposed at that level.

Unfortunately, this requires that consuming code check whether the object implements IDisposable if they want to dispose of it:

IFoo foo = ...;
IDisposable disposableFoo = foo as IDisposable;
if (disposableFoo != null)
{
    disposableFoo.Dispose();
}

What are your thoughts?  Do you agree?

Comments

  • Anonymous
    March 13, 2009
    I agree. IDisposable is only relevant to an instance of a class and doesn't mean anything for an interface. To place it on an interface would be an unnecessary constraint. As a side note, you may be interested in this: <a href="http://www.neovolve.com/post/2008/07/03/reflection-pop-quiz-does-interface-inheritance-exist.aspx'>http://www.neovolve.com/post/2008/07/03/reflection-pop-quiz-does-interface-inheritance-exist.aspx">http://www.neovolve.com/post/2008/07/03/reflection-pop-quiz-does-interface-inheritance-exist.aspx</a>

  • Anonymous
    March 13, 2009
    This reasoning might also apply to abstract classes such as Stream - a MemoryStream, for example, doesn't need disposing. The counterargument is that manual disposal is clumsy - and in most cases requires a try/finally block. It's also less discoverable - consumers might not realize that they have to dispose an object if working via interfaces. For interfaces such as IDbConnection and IDataReader - whose implementations always need IDisposable, it would be awkward having to deal with a cast and try/finally block whenever it was used. The following code is the simplest and most natural: using (IDataReader reader = myIDbCommand.ExecuteReader()) {   ... } Same deal with streams. So maybe it depends on the particular situation.