Just wondering why Enumerable.Range
implements IDisposable
.
I understand why IEnumerator<T>
does, but IEnumerable<T>
doesn't require it.
(I discovered this while playing with my .Memoise() implementation, which has statement like
if (enumerable is IDisposable)
((IDisposable)enumerable).Dispose();
in its "source finished" method that I had placed a breakpoint on out of curiousity, and was triggered by a test.)
Enumerable.Range
uses yield return
in its method body. The yield return
statement produces an anonymous type that implements IDisposable
, under the magic of the compiler, like this:
static IEnumerable<int> GetNumbers()
{
for (int i = 1; i < 10; i += 2)
{
yield return i;
}
}
After being compiled, there is an anonymous nested class like this:
[CompilerGenerated]
private sealed class <GetNumbers>d__0
: IEnumerable<int>, IEnumerable, IEnumerator<int>, IEnumerator, IDisposable
{
//the implementation
//note the interface is implemented explicitly
void IDisposable.Dispose() { }
}
so the result is
a IDisposable
. In this example, the Dispose
method leaves empty. I think the reason is that there is nothing need to be disposed. If you yield return
a type that contains unmanaged resources, you may get a different compiling result. (NOT SURE about it)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With