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