views:

94

answers:

5

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)
     {
     //do something

     } 
}
+2  A: 

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.

Mark Byers
edited my question to give examples of what I want to do
Sam Holder
@bebop: I think if you choose the list that disposes, it is maybe a little more convenient now for your current situation, but you are implying that your client should always dispose the objects simultaneously. Is there a fundamental reason why the objects must be disposed at the same time, and could this be modelled in a different way by having one resource that needs disposing instead? Your situation reminds me a little of connections and transactions, or a file with many readers. Perhaps you could use these classes as inspiration for your design?
Mark Byers
+1  A: 

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.

Hans Passant
hmm interesting. I suppose there could be situations where some elements in the list are returned to another method, and then disposing the list could cause problems
Sam Holder
+1  A: 

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
}
Mongus Pong
Why are you using 'if (o is IDisposable) { (o as IDisposable).Dispose(); }'? Why not just use 'o as IDisposable' then test for null?
thecoop
@thecoop I dont really see what I would gain from that approach. Id have to either use a temp variable or do if ((o as IDisposabe) != null) {(o as IDisposable).Dispose()}. I feel this way is cleaner, but feel free to use either, I dont think theres really much in it. :)
Mongus Pong
I think a double (o as IDisposable) ticks off a Static Code Analysis rule, saying you should create a variable for this to avoid unnecessary repeated casts. (Right?)
peSHIr
yeah, this does have unnecessary casts I think and doing it thecoops way seems better, even if you need a temporary variable.
Sam Holder
Fair play! Will edit :0)
Mongus Pong
a few of the answers were candidates for the answer but I think this suits my needs best, I can use it when I want to dispose the list, and when I don't want to I can keep things the way they are. cheers
Sam Holder
No probs! :) Pleasure.
Mongus Pong
+1  A: 

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 ;)

Mongus Pong
.net 2.0, but thanks for the suggestion
Sam Holder
+2  A: 

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.

Marc Gravell