Почему Enumerable.Range реализует IDisposable?

Просто интересно, почему Enumerable.Range реализует IDisposable.

Я понимаю, почему IEnumerator<T> делает, но IEnumerable<T> не требует его.


(я обнаружил это во время игры с моей реализацией .Memoise(), которая имеет оператор вроде

if (enumerable is IDisposable)
    ((IDisposable)enumerable).Dispose();

в своем методе "исходный законченный", который я поставил точку останова из любопытства и был вызван тестом.)

Ответ 1

Enumerable.Range использует yield return в своем теле метода. Оператор yield return создает анонимный тип, который реализует IDisposable под маской компилятора, например:

static IEnumerable<int> GetNumbers()
{
    for (int i = 1; i < 10; i += 2)
    {
        yield return i;
    }
}

После компиляции существует анонимный вложенный класс:

[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() { }
}

поэтому результат is a IDisposable. В этом примере метод Dispose остается пустым. Я думаю, причина в том, что нет ничего, что нужно было бы утилизировать. Если вы yield return тип, который содержит неуправляемые ресурсы, вы можете получить другой результат компиляции. (НЕ УВЕРЕННО об этом)