Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Enumerable.Range Implement IDisposable?

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

like image 590
Fowl Avatar asked Jul 04 '12 03:07

Fowl


1 Answers

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)

like image 162
Cheng Chen Avatar answered Sep 28 '22 03:09

Cheng Chen