简体   繁体   English

为什么 IEnumerator<T> 继承自 IDisposable 而非泛型 IEnumerator 不?

[英]Why does IEnumerator<T> inherit from IDisposable while the non-generic IEnumerator does not?

I noticed that the generic IEnumerator<T> inherits from IDisposable, but the non-generic interface IEnumerator does not.我注意到通用IEnumerator<T>继承自 IDisposable,但非通用接口 IEnumerator 没有。 Why is it designed in this way?为什么要这样设计?

Usually, we use foreach statement to go through a IEnumerator<T> instance.通常,我们使用 foreach 语句遍历IEnumerator<T>实例。 The generated code of foreach actually has try-finally block that invokes Dispose() in finally. foreach 生成的代码实际上有 try-finally 块,它在 finally 中调用 Dispose()。

Basically it was an oversight.基本上这是一个疏忽。 In C# 1.0, foreach never called Dispose 1 .在 C# 1.0 中, foreach从不调用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 .使用 C# 1.2(在 VS2003 中引入 - 奇怪的是没有 1.1) foreach开始在finally块中检查迭代器是否实现了IDisposable - 他们必须这样做,因为回顾性地使IEnumerator扩展IDisposable会破坏每个人的实现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 .如果他们发现foreach首先处理迭代器很有用,我敢肯定IEnumerator会扩展IDisposable

When C# 2.0 and .NET 2.0 came out, however, they had a fresh opportunity - new interface, new inheritance.然而,当 C# 2.0 和 .NET 2.0 出现时,他们有了一个新的机会——新的接口、新的继承。 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 .让接口扩展IDisposable更有意义,这样您就不需要在 finally 块中进行执行时检查,现在编译器知道如果迭代器是IEnumerator<T>它可以发出无条件调用Dispose

EDIT: It's incredibly useful for Dispose to be called at the end of iteration (however it ends).编辑:在迭代结束时调用Dispose非常有用(但是它结束了)。 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.迭代器块生成Dispose实现,它确保与迭代器的“当前执行点”相关的任何finally块在它被释放时都会被执行——这样你就可以在迭代器中编写正常的代码,并且应该适当地进行清理。


1 Looking back at the 1.0 spec, it was already specified. 1回顾 1.0 规范,它已经被指定了。 I haven't yet been able to verify this earlier statement that the 1.0 implementation didn't call Dispose .我还没有能够验证之前的声明,即 1.0 实现没有调用Dispose

IEnumerable<T> doesn't inherit IDisposable. IEnumerable<T> 不继承 IDisposable。 IEnumerator<T> does inherit IDisposable however, whereas the non-generic IEnumerator doesn't.然而,IEnumerator<T> 确实继承了 IDisposable,而非泛型 IEnumerator 则没有。 Even when you use foreach for a non-generic IEnumerable (which returns IEnumerator), the compiler will still generate a check for IDisposable and call Dispose() if the enumerator implements the interface.即使您将foreach用于非泛型 IEnumerable(返回 IEnumerator),编译器仍会生成对 IDisposable 的检查,并在枚举器实现接口时调用 Dispose()。

I guess the generic Enumerator<T> inherits from IDisposable so there doesn't need to be a runtime type-check—it can just go ahead and call Dispose() which should have better performance since it can be probably be optimized away if the enumerator has an empty Dispose() method.我猜通用 Enumerator<T> 继承自 IDisposable,因此不需要进行运行时类型检查——它可以继续调用应该具有更好性能的 Dispose(),因为如果枚举器有一个空的 Dispose() 方法。

I reasontly wrote a library where I used IEnumerable of T / IEnumerator of T where users of the library could implement custom iterators they should just implement IEnumerator of T .我合理地编写了一个库,其中我使用IEnumerable of T IEnumerator of T / IEnumerable of T IEnumerator of T库的用户可以在其中实现自定义迭代器,他们应该只实现IEnumerator of T

I found it very strange that IEnumerator of T would inherit from IDisposable.我发现 T 的 IEnumerator 会从 IDisposable 继承非常奇怪。 We implement IDisposable if we want to free unmanaged resources right?如果我们想释放非托管资源,我们实施 IDisposable 对吗? So it would only be relevant for enumerators that actually hold unmanaged resources - like an IO stream etc. Why not just let users implement both IEnumerator of T and IDisposable on their enumerator if it makes sense?所以它只与实际持有非托管资源的枚举器相关——比如 IO 流等。如果有意义,为什么不让用户在他们的枚举器上实现 T 的 IEnumerator 和 IDisposable 呢? In my book this violates the single responsibility principle - Why mix enumerator logic and disposing objects.在我的书中,这违反了单一职责原则 - 为什么混合枚举器逻辑和处理对象。

Does IEnumerable` inherit IDisposing? IEnumerable` 是否继承了 IDisposing? According to the .NET reflector or MSDN .根据 .NET 反射器或MSDN Are you sure you're not confusing it with IEnumerator ?你确定你没有将它与IEnumerator混淆吗? That uses IDisposing because it only for enumerating a collection and not meant for longevity.使用 IDisposing 是因为它仅用于枚举集合而不是为了长寿。

A bit hard to be definitive on this, unless you manage to get a response from AndersH himself, or someone close to him.对此有点难以确定,除非您设法得到 AndersH 本人或与他关系密切的人的回应。

However, my guess is that it relates to the "yield" keyword that was introduced in C# at the same time.但是,我的猜测是它与同时在 C# 中引入的“yield”关键字有关。 If you look at the code generated by the compiler when "yield return x" is used, you'll see the method wrapped up in a helper class that implements IEnumerator;如果您查看使用“yield return x”时编译器生成的代码,您会看到该方法包含在实现 IEnumerator 的辅助类中; having IEnumerator descend from IDisposable ensures that it can clean up when enumeration is complete.让 IEnumerator 从 IDisposable 下降确保它可以在枚举完成时进行清理。

IIRC The whole thing about having IEnumerable<T> and IEnumerable is a result of IEnumerable predating .Net's template stuff. IIRC 关于拥有IEnumerable<T>IEnumerable的整个事情是IEnumerable早于 .Net 的模板内容的结果。 I suspect that your question is in the same way.我怀疑你的问题也是如此。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么泛型IList &lt;&gt;不继承非泛型IList - Why generic IList<> does not inherit non-generic IList 为什么要使用通用ICollection <T> 不继承一些带有Count属性的非通用接口? - Why generic ICollection<T> does not inherit some non-generic interface with Count property? 为什么这个 IEnumerator function 不起作用 - Why does this IEnumerator function not work 为什么我必须定义IEnumerator <T> .Current&IEnumerator.Current,它实现了什么? - Why must I define IEnumerator<T>.Current & IEnumerator.Current, and what does that achieve? foreach是否更喜欢IEnumerable <T> 或IEnumerator <T> - Does foreach prefer IEnumerable<T> or IEnumerator<T> 为什么我的 IEnumerator<AppiumWebElement> 没有 .Where()? - Why does my IEnumerator<AppiumWebElement> not have .Where()? IEnumerator vs IEnumerator <T> - IEnumerator vs IEnumerator<T> 为什么接口 IEnumerable 返回 IEnumerator GetEnumemrator()? 为什么不只实现接口 IEnumerator? - Why does interface IEnumerable return IEnumerator GetEnumemrator()? Why not just implement interface IEnumerator? 为什么 using 语句在 IEnumerator 上起作用,它有什么作用? - Why does the using statement work on IEnumerator and what does it do? 为什么存在通用和非通用IComparable接口? - Why does a generic and a non-generic IComparable interface exist?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM