我注意到,泛型IEnumerator<T>
继承自IDisposable,但非泛型接口IEnumerator却没有。为什么以这种方式设计?
通常,我们使用foreach语句来遍历一个IEnumerator<T>
实例。foreach的生成代码实际上具有try-finally块,该块最终将调用Dispose()。
Answers:
基本上,这是一个疏忽。在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<T>
it,则可以发出对to的无条件调用Dispose
。
编辑:Dispose
在迭代结束时调用它非常有用(但是它结束了)。这意味着迭代器可以保留资源-这使得它可以逐行读取文件。迭代器块生成Dispose
实现,以确保finally
与迭代器的“当前执行点”相关的所有块在被处置时都被执行-因此您可以在迭代器中编写常规代码,并且清理工作应适当进行。
1回顾1.0规格,它已经被指定。我尚未能够验证1.0实施未调用的此较早的声明Dispose
。
IEnumerable
以确保GetEnumerator
将处置从中返回的任何可抛弃对象。不应该认为是破损的代码。
Dispose
逻辑的C#版本foreach
在VisualBasic.Collection
该类上的表现都非常差(这在很多方面都令人讨厌和古怪,但是-与那个时代的其他Microsoft集合不同-允许删除项目)在枚举期间)。该Collection
班避免持有优秀统计员任何强引用,并清除它们,如果他们得到垃圾收集,但如果集合枚举GC周期,这些普查员之间多次不清理,就会得到非常缓慢。
IEnumerable <T>不继承IDisposable。IEnumerator <T>确实继承了IDisposable,而非通用IEnumerator则没有。即使将foreach用于非通用IEnumerable(返回IEnumerator),如果枚举器实现接口,编译器仍将生成IDisposable的检查并调用Dispose()。
我猜想通用的Enumerator <T>是从IDisposable继承的,因此不需要运行时类型检查-它可以继续调用Dispose()来提高性能,因为如果枚举器有一个空的Dispose()方法。
IEnumerable
at编译,那么它可以优化对的调用Dispose
,也可以优化对类型的检查。
我知道这是一个古老的讨论,但是我有理由编写了一个库,在该库中我使用了T的IEnumerable / T的IEnumerator,该库的用户可以实现自定义迭代器,而他们应该只实现T的IEnumerator。
我发现T的IEnumerator继承自IDisposable很奇怪。如果我们想释放未管理的资源,我们实现IDisposable吗?因此,这仅与实际上拥有非托管资源(例如IO流等)的枚举器有关。为什么不让用户在其枚举器上同时实现T的IEnumerator和IDisposable呢?在我的书中,这违反了单一责任原则-为什么要混合枚举器逻辑和布置对象。
GetEnumerator
返回需要清除的对象(例如,因为它正在从文件中读取将要关闭的数据行),则知道何时不再需要枚举数的实体必须具有某种方式将该信息传递给某个实体,该实体可以执行清理。 IDisposable
对于Liskov替代原则,其行为是向后的,因为退回可能需要清理的东西的工厂不能安全地代替承诺退回不需要的东西的工厂,但是反向替换是安全的并且应该是合法的。
IDisposable
上IEnumerator<T>
是有点混乱,我发现它有助于检查出如何Enumerator
的List<T>
实现IDisposable
在.NET源。请注意,Enumerator
struct
的Dispose
方法如何,但里面什么也没有。请注意,此IDisposable
行为绝不意味着“ AList<Bitmap>
应该将其Bitmap
放入foreach
! ”
除非您设法从AndersH本人或与他亲近的人那里得到回应,否则很难确定这一点。
但是,我的猜测是,它与C#中同时引入的“ yield”关键字有关。如果查看使用“ yield return x”时由编译器生成的代码,您会看到该方法包装在实现IEnumerator的帮助器类中;将IEnumerator继承自IDisposable可以确保枚举完成后可以清除它。
VisualBasic.Collection
类将表现不佳(几个数量级慢于正常),如果被创建并没有被设置的废弃许多枚举器。关联需要Dispose
有IEnumerable
很明显这样的发布之前.net 1.0, but probably late enough that changing
IEnumerable`继承IDisposable
会影响发行计划。
IEnumerable.GetEnumerator
(非泛型)的IDisposable
表现呢?