Designing an interface where only some implementations require IDisposable

You are developing the IFoo interface

 public interface IFoo { void Bar(); } 

Say there are five implementations of this interface. Two of these implementations must also implement IDisposable , as they use unmanaged resources. From the perspective of the caller, it would be easiest if IFoo implemented IDisposable , so any IFoo could be wrapped in a using block, but, of course, some of the implementations would be clogged with empty Dispose() methods. Just curious if there are other ways to do this?

EDIT

Its clearly better to have IFoo implement IDisposable to take any responsibility from the client. How would they even know when and when not to check whether something is possible? They will have to do this with everything else. Everyone seems to agree that a few empty Dispose () methods won't hurt anyone.

The best thing that can arise in this question is how to correctly check whether something can be accessed with the help of “how” and “use” in Mark Gravel’s answer.

+7
source share
7 answers

I suspect that I just require IDisposable() - no-op Dispose() not a big consignment note.

If you cannot be sure that this is one-time, the following is quite effective:

 var mightBeDisposable = GetBlah(); using(mightBeDisposable as IDisposable) { // etc } 
+7
source

In the .NET Framework there are precedents for interfaces that implement IDisposable - for example, IComponent , IDataReader .

This seems like a reasonable model when you expect most implementations to require deletion.

+3
source

Although objects that implement interfaces generally promise capabilities or characteristics that are not common to objects without these interfaces, and although IDisposable is an interface, the fact that an object implements IDisposable does not promise any ability or characteristics will not be present in objects that they don’t do it. Instead, the fact that an object implements IDisposable implies that it lacks a characteristic characteristic of objects that do not implement it: the ability of anyone who acquires or contains a link refuses it, regardless of whether the object can or should to be cleaned first.

If code that uses a particular type of interface is usually not the last link maintained, then there is no need for an interface to implement IDisposable . Even if some implementations cannot be safely left behind, it does not matter to any users of the instance other than the last containing the link. If this user usually knows more about a particular type than the interface implies, the user will find out if the object needs to be cleaned, if the interface points to it.

On the other hand, if the last user of the object knows nothing about this at all, except for the fact that he implements an interface, then this interface should inherit IDisposable even (perhaps especially!), If only a small part of the implementations require cleaning. Consider the case of IEnumerable compared to IEnumerable<T> . Any code that calls IEnumerable<T>.GetEnumerator() will get what is likely to be the only link anywhere in the universe for an object that implements IDisposable . Therefore, this code takes responsibility for ensuring that Dispose called to this link. Any code that calls IEnumerable<T>.GetEnumerator() and does not call Dispose on the returned value, and does not pass it to another code that promises does this, is violated.

The type returned by non-generic IEnumerable.GetEnumerator does not implement IDisposable . This suggests that, in his opinion, the code that calls IEnumerable.GetEnumerator is not responsible for its use. Unfortunately, this implication is incorrect. The code that calls IEnumerable.GetEnumerator is responsible for ensuring that if the returned instance returns IDisposable objects, then its Dispose method must be called. Code that does not support this responsibility is no less corrupted than code that cannot order the return from IEnumerable<T>.GetEnumerator . A return type failure of IEnumerable.GetEnumerator (i.e. IEnumerator ) to implement IDisposable does not eliminate the responsibility of the caller to clean up the returned object. It just makes that responsibility more onerous and increases the likelihood that the code will not be able to do this.

+2
source

You can create a one-time version of your interface that better shows your intent:

 public interface IDisposableFoo : IFoo, IDisposable { } 

Any class that inherits this interface can still be considered as IFoo. Perhaps the problem is having to check if your IFoo object is a one-time version before considering it as such, but it's pretty easy.

+1
source

If you don't mind adding the code to your calling site, you can simply do the following:

 IFoo foo = GetMeSomeFoo(); foo.UseFoo(); var disposableFoo = foo as IDisposable; if (disposableFoo != null) disposableFoo.Dispose(); 

Not very, but not polluting your interface. It does not guarantee that the caller will do all this.

EDIT: as Hans Passant pointed out, it is essentially equal

 IFoo foo = GetMeSomeFoo(); using (foo as IDisposable) { foo.UseFoo(); } 
+1
source

I would not force IFoo to implement IDisposable, since it is against SOLID. You can get IDisposableFoo from IFoo if you want, or you can check (or even a custom method that wraps IFoo in a DisposableAdapter and checks for IDisposable) if you need it.

 class DisposableAdapter : IDisposable, IFoo { IFoo _obj; public DisposableAdapter(IFoo obj) { _obj = obj; } public void Dispose() { if (_obj is IDisposable) ((IDisposable)obj).Dispose(); } // copy IFoos implementations from obj } 

using

 using(var foo = new DisposableAdapter(myFoo)) //... use foo just as you had myFoo 
+1
source

You either need two interfaces, one of which implements IDisposable, and the other IFoo and IDisposableFoo or just one-time IFoo .

There is no harm in having some empty IDisposable implementations. Given that you already have some that need to be disposed of, this seems like a likely use case.

0
source

All Articles