It's recently been pointed out to me that various Linq extension methods (such as Where
, Select
, etc) return an IEnumerable<T>
that also happens to be IDisposable
. The following evaluates to True
new int[2] {0,1}.Select(x => x*2) is IDisposable
Do I need to dispose of the results of a Where
expression?
Whenever I call a method returning IEnumerable<T>
, am I (potentially) accepting responsibility for calling dispose when I've finished with it?
No, you don't need to worry about this.
The fact that they return an IDisposable
implementation is an implementation detail - it's because iterator blocks in the Microsoft implementation of the C# compiler happen to create a single type which implements both IEnumerable<T>
and IEnumerator<T>
. The latter extends IDisposable
, which is why you're seeing it.
Sample code to demonstrate this:
using System;
using System.Collections.Generic;
public class Test
{
static void Main()
{
IEnumerable<int> foo = Foo();
Console.WriteLine(foo is IDisposable); // Prints True
}
static IEnumerable<int> Foo()
{
yield break;
}
}
Note that you do need to take note of the fact that IEnumerator<T>
implements IDisposable
. So any time you iterate explicitly, you should dispose of it properly. For example, if you want to iterate over something and be sure that you'll always have a value, you might use something like:
using (var enumerator = enumerable.GetEnumerator())
{
if (!enumerator.MoveNext())
{
throw // some kind of exception;
}
var value = enumerator.Current;
while (enumerator.MoveNext())
{
// Do something with value and enumerator.Current
}
}
(A foreach
loop will do this automatically, of course.)