为什么IEnumerator <T>从IDisposableinheritance,而非genericsIEnumerator没有?

我注意到genericsIEnumerator<T>从IDisposableinheritance,但非generics接口IEnumerator不。 为什么这样devise?

通常,我们使用foreach语句来通过一个IEnumerator<T>实例。 foreach生成的代码实际上有最后调用Dispose()的try-finally块。

基本上这是一个疏忽。 在C#1.0中, foreach 从来没有叫过Dispose 1 。 随着C#1.2(在VS2003中引入 – 没有1.1,奇怪) foreach开始检查finally块是否迭代器实现了IDisposable – 他们必须这样做,因为追溯使IEnumerator扩展IDisposable将破坏每个人的执行IEnumerator 。 如果他们想出了foreach处理迭代器的用处,我确定IEnumerator会扩展IDisposable

当C#2.0和.NET 2.0推出时,他们有了新的机会 – 新界面,新inheritance。 让接口扩展IDisposable使得在finally块中不需要执行时间检查更有意义,现在编译器知道如果迭代器是一个IEnumerator<T>它可以发出一个无条件的调用来Dispose

编辑:它是令人难以置信的有用的Dispose被称为在迭代结束(但它结束)。 这意味着迭代器可以保持资源 – 这使得它可以逐行读取文件。 迭代器块生成器Dispose实现,确保当处理迭代器时,与迭代器的“当前执行点”相关的任何finally块都被执行 – 这样就可以在迭代器中编写正常的代码,并且适当地进行清理。


1回顾1.0规范,它已经被指定。 我还没有能够validation这个早期的声明,1.0实现没有调用Dispose

IEnumerable <T>不会inheritanceIDisposable。 IEnumerator <T>确实inheritance了IDisposable,然而非genericsIEnumerator却没有。 即使当您使用foreach作为非genericsIEnumerable(它将返回IEnumerator)时,编译器仍然会生成对IDisposable的检查,并在枚举器实现该接口时调用Dispose()。

我猜generics枚举器<T>从IDisposableinheritance,所以不需要是一个运行时types检查,它可以继续前进,并调用Dispose()应该有更好的性能,因为它可以被优化,如果枚举器有一个空的Dispose()方法。

我知道这是一个古老的讨论,但我重写了一个库,我使用T的T / IEnumerator IEnumerable库的用户可以实现自定义迭代器,他们应该只是实现T的IEnumerator

我发现T的IEnumerator会从IDisposableinheritance,这很奇怪。 如果我们想要释放无用的资源,我们实现IDisposable? 所以它只与实际上持有非托pipe资源的枚举器相关 – 比如IOstream等。为什么不让用户在他们的枚举器上实现T和IDisposable的IEnumerator? 在我的书中,这违反了单一责任原则 – 为什么混合枚举器逻辑和处置对象。

IEnumerable`是否inheritanceIDisposing? 根据.NETreflection器或MSDN 。 你确定你没有与IEnumerator混淆吗? 这使用IDisposing,因为它只是为了枚举集合而不是为了长寿。

有一点难以确定,除非你能得到AndersH本人或他身边的人的回应。

不过,我的猜测是它与C#中同时引入的“yield”关键字有关。 如果您在使用“yield return x”时查看由编译器生成的代码,您将看到包装在实现IEnumerator的助手类中的方法; IEnumerator从IDisposable下降确保它可以在枚举完成时清理。

IIRC有关IEnumerable<T>IEnumerable的整个事情是IEnumerable早于.NET的模板的东西的结果。 我怀疑你的问题是以同样的方式。