Should I have methods which return lists of Disposable instances?
I have a class, instances of which need to be disposed. I also have several classes that produce these instances, either singly or lists of them.
Should I return IList<MyClass>
from my methods or should I create a class that is MyClassCollection
which is also disposable and return this instead?
EDIT:
My main reason for asking is that I have ended up doing this quite a lot:
IList<MyObject> list = GetList();
foreach(MyObject obj in list)
{
//do something
obj.Dispose();
}
and it seems that I would be better doing:
using (IList<MyObject> list = GetList())
{
foreach(MyObject obj in list)
{
//d开发者_如何学编程o something
}
}
It may be easier to generate a sequence of items (IEnumerable<T>
) rather than a list - there are ways that you can make the lifetime of each tied into the iterator, so that:
- you only have one at a time (I assume they are expensive)
- they get disposed when their time is up
- they all get disposed, even in error
This is a topic that I explored here using LINQ, but there are other ways too, if your source is (or can be) a sequence.
It depends on how you will use them, both seem reasonable options. If you know that you will need to dispose all the objects at the same time, then perhaps making the list disposable makes sense, but if the objects could have different lifetimes, I would just return an ordinary list.
Perhaps you could make a generic IDisposableList<T>
with a constraint on T where T : IDisposable
and have your class implement IDisposable
by calling Dispose
on all its elements? Then you can reuse this class for all your different IDisposable
types.
It is completely up to the client code to call your Dispose() method. Only it knows when it is done using the objects. You cannot help in any way because you don't know what that code will look like. Creating list objects that dispose their elements is not a good idea. The framework contains no collection object that does this. You'll just confuse the client code programmer.
A container class would probably be cleaner in these instances. You can then continue using the standard collection classes, and you are forced to be more explicit about when the items will need disposing at the end.
public class ListScope : IDisposable
{
private IList list;
public ListScope(IList list)
{
this.list = list;
}
#region IDisposable Members
public void Dispose ()
{
foreach ( object o in this.list )
{
IDisposable disposable = ( o as IDisposable );
if (disposable != null)
disposable.Dispose ();
}
}
#endregion
}
You could use as :
using ( new ListScope ( list ) )
{
// Do stuff with list
}
You could also use an Extension if you wanted :
static class Extensions
{
public static void DoStuffAndDisposeElements<T> ( this List<T> list, Action<T> action )
{
list.ForEach ( x => { action ( x );
IDisposable disposable = (x as IDisposable);
if ( disposable != null )
disposable.Dispose ();
} );
}
}
which you could call by :
getList().DoStuffAndDisposeElements ( x => doStuff(x));
Not sure how much you would gain from it, but there may be situations where it would be useful ;)
精彩评论