为什么 IEnumerator<T>继承自 IDisposable 而非通用 IEnumerator 不? [英] Why does IEnumerator<T> inherit from IDisposable while the non-generic IEnumerator does not?
问题描述
我注意到泛型 IEnumerator
继承自 IDisposable,但非泛型接口 IEnumerator 没有.为什么要这样设计?
I noticed that the generic IEnumerator<T>
inherits from IDisposable, but the non-generic interface IEnumerator does not. Why is it designed in this way?
通常,我们使用 foreach 语句来遍历 IEnumerator
实例.foreach 生成的代码实际上有 try-finally 块,它在 finally 中调用 Dispose().
Usually, we use foreach statement to go through a IEnumerator<T>
instance. The generated code of foreach actually has try-finally block that invokes Dispose() in finally.
推荐答案
基本上这是一个疏忽.在 C# 1.0 中,foreach
never 调用 Dispose
1.使用 C# 1.2(在 VS2003 中引入 - 奇怪的是没有 1.1)foreach
开始检查 finally
块中的迭代器是否实现了 IDisposable
- 他们不得不这样做,因为追溯性地使 IEnumerator
扩展 IDisposable
会破坏每个人对 IEnumerator
的实现.如果他们发现 foreach
首先处理迭代器很有用,我敢肯定 IEnumerator
会扩展 IDisposable
.
Basically it was an oversight. In C# 1.0, foreach
never called Dispose
1. With C# 1.2 (introduced in VS2003 - there's no 1.1, bizarrely) foreach
began to check in the finally
block whether or not the iterator implemented IDisposable
- they had to do it that way, because retrospectively making IEnumerator
extend IDisposable
would have broken everyone's implementation of IEnumerator
. If they'd worked out that it's useful for foreach
to dispose of iterators in the first place, I'm sure IEnumerator
would have extended IDisposable
.
然而,当 C# 2.0 和 .NET 2.0 出现时,他们有了新的机会 - 新界面,新继承.让接口扩展 IDisposable
更有意义,这样你就不需要在 finally 块中进行执行时检查,现在编译器知道迭代器是否是 IEnumerator<T>
它可以发出对 Dispose
的无条件调用.
When C# 2.0 and .NET 2.0 came out, however, they had a fresh opportunity - new interface, new inheritance. It makes much more sense to have the interface extend IDisposable
so that you don't need an execution-time check in the finally block, and now the compiler knows that if the iterator is an IEnumerator<T>
it can emit an unconditional call to Dispose
.
在迭代结束时调用 Dispose
非常有用(不管它结束).这意味着迭代器可以保留资源 - 这使得它可以逐行读取文件.迭代器块生成 Dispose
实现,确保与迭代器的当前执行点"相关的任何 finally
块在它被释放时被执行——这样你就可以编写正常的代码在迭代器和清理中应该适当地发生.
It's incredibly useful for Dispose
to be called at the end of iteration (however it ends). It means the iterator can hold on to resources - which makes it feasible for it to, say, read a file line by line. Iterator blocks generate Dispose
implementations which make sure that any finally
blocks relevant to the "current point of execution" of the iterator are executed when it's disposed - so you can write normal code within the iterator and clean-up should happen appropriately.
1 回顾 1.0 规范,它已经被指定了.我还没有能够验证之前的声明,即 1.0 实现没有调用 Dispose
.
1 Looking back at the 1.0 spec, it was already specified. I haven't yet been able to verify this earlier statement that the 1.0 implementation didn't call Dispose
.
这篇关于为什么 IEnumerator<T>继承自 IDisposable 而非通用 IEnumerator 不?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!