Search code examples
c#oopextension-methodsdisposeidisposable

Extension method to Dispose List not working


I've written a simple extension method to dispose off all the items in a list:

public static void Dispose(this List<IDisposable> list) {
    for (int i = 0, il = list.Count; i < il; i++) {
        list[i].Dispose();
    }
    list.Clear();
}

But when I try to use it, the VS IntelliSense doesn't list it in the drop down, and cannot find the method at compile time. How do I make it work?

List<Bitmap> bitmaps = new List<Bitmap>();
bitmaps.Dispose(); // Error: List<Bitmap> does not contain a definition for Dispose()

Solution

  • Try this:

    public static void Dispose<T>(this List<T> list) where T : IDisposable {
        for (int i = 0, il = list.Count; i < il; i++) {
            list[i].Dispose();
        }
        list.Clear();
    }
    

    Quick explanation: A List<Bitmap> is a List Of Bitmaps, not a List Of IDisposables even though Bitmap itself is an IDisposable. A List Of Bitmaps however is a List Of T or more exactly: a List Of T where T implements IDisposable. So the compiler happily accepts above extension method.

    Further (just because this makes for such a nice example):

    List<T> is said to be invariant with regards to its type parameter. Hence the following assignment is not allowed and will produce a compiler error:

    List<IDisposable> l = new List<Bitmap>();
    

    and neither is the following type conversion:

    List<Bitmap> lb = new List<Bitmap>();
    List<IDisposable> ld = (List<IDisposable>)lb;
    

    If you are on .NET 4 however (where variance of type parameters was introduced) and you use a generic type with a covariant type parameter (such as IEnumerable<out T>) the following type conversion becomes valid:

    List<Bitmap> lb = new List<Bitmap>();
    IEnumerable<IDisposable> ld = lb;
    

    and is indeed done implicitly for you. In this case, the following extension method works too:

    // In a static class:
    public static void Dispose(this IEnumerable<IDisposable> e) {
        foreach(var x in e) {
            x.Dispose();
        }
    }
    
    // Somewhere else:
    List<Bitmap> l = new List<Bitmap>();
    l.Dispose();