为什么IEnumerator< T>继承自IDisposable,而非通用的IEnumerator没有?

StackOverflow https://stackoverflow.com/questions/232558

  •  04-07-2019
  •  | 
  •  

我注意到泛型 IEnumerator< T> 继承自IDisposable,但非泛型接口IEnumerator却没有。为什么这样设计?

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

有帮助吗?

解决方案

基本上这是一个疏忽。在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出现时,他们有了一个新的机会 - 新的界面,新的继承。让接口扩展 IDisposable 更有意义,这样你就不需要在finally块中执行执行时检查,现在编译器知道如果迭代器是 IEnumerator&lt ; T> 它可以发出对 Dispose 的无条件调用。

编辑:在迭代结束时调用 Dispose 是非常有用的(但它结束了)。这意味着迭代器可以保留资源 - 这使得它可以逐行读取文件。迭代器块生成 Dispose 实现,这些实现确保任何 finally 块与“当前执行点”相关。迭代器在处理时执行 - 这样你就可以在迭代器中编写普通代码,并且应该适当地进行清理。


1 回顾1.0规范,已经指定了。我还没有能够验证这个早先的声明,即1.0实现没有调用 Dispose

其他提示

的IEnumerable< T>不继承IDisposable。的IEnumerator< T>然而,继承IDisposable,而非通用IEnumerator没有。即使将 foreach 用于非通用IEnumerable(返回IEnumerator),编译器仍会生成对IDisposable的检查,如果枚举器实现了接口,则调用Dispose()。

我猜通用的枚举器< T>继承自IDisposable所以不需要运行时类型检查—它可以继续调用Dispose(),它应该具有更好的性能,因为如果枚举器有一个空的Dispose,它可能会被优化掉(方法。

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

我发现很奇怪,T的IEnumerator会从IDisposable继承。如果我们想要释放无人资源,我们实施IDisposable吗?因此,它只与实际拥有非托管资源的枚举器相关 - 如IO流等。为什么不让用户在其枚举器上实现T的IEnumerator和IDisposable是否有意义?在我的书中,这违反了单一责任原则 - 为什么要混合枚举器逻辑和处理对象。

IEnumerable`是否继承IDisposing?根据.NET反射器或 MSDN 。您确定不要将其与 IEnumerator 混淆吗?它使用IDisposing,因为它只用于枚举集合而不是长寿。

有点难以确定,除非你设法得到AndersH本人或与他亲近的人的回复。

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

IIRC关于 IEnumerable< T> IEnumerable 的全部事情是 IEnumerable 早于.Net的模板内容的结果。我怀疑你的问题是一样的。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top