【发布时间】:2009-09-23 19:43:22
【问题描述】:
根据我在http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx 上看到的内容以及 Jon Skeet 的文章,c# 规范本身就是这么说的。会是什么原因?
【问题讨论】:
根据我在http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx 上看到的内容以及 Jon Skeet 的文章,c# 规范本身就是这么说的。会是什么原因?
【问题讨论】:
这不是我阅读C# spec [Word doc] 的方式。第 10.14.4 节“枚举器对象”,状态:
...[E]numerator 对象不支持 IEnumerator.Reset 方法。调用此方法会引发 System.NotSupportedException。
但是,这部分(和语句)特定于“枚举器对象”,其定义为:
当使用迭代器块实现返回枚举器接口类型的函数成员时,调用函数成员不会立即执行迭代器块中的代码。而是创建并返回一个枚举器对象。
换句话说,“枚举器对象”是编译器生成的IEnumerator1。每个IEnumerator 都没有限制,只有从迭代器块(又名yield)生成的那些。
至于为什么?我怀疑是因为在一般情况下这有点不可能 - 如果不保存每个值以及随之而来的内存限制。再加上IEnumerator.Reset() 很少使用(您最后一次重置枚举器是什么时候?)以及MSDN specifically calls out that it need not be implemented:
为 COM 互操作性提供了 Reset 方法。它不一定需要实施;相反,实现者可以简单地抛出 NotSupportedException。
您可以在没有人真正注意到的情况下消除很多复杂性。
至于要求它抛出2,我想这比让实现者决定要简单。 IMO,要求抛出有点多 - 编译器(或其他实现1)可能会生成一个重置方法的合理情况,但我不认为它是真实的也有问题。
1 从技术上讲,该规范保留了其他实现的可能性:
枚举器对象通常是编译器生成的枚举器类的实例,它封装迭代器块中的代码并实现枚举器接口,但其他实现方法也是可能的。
但我不知道任何其他具体实现。无论如何,为了符合要求,“枚举器对象”的其他实现也必须抛出 NotSupportedException。
2 Nitpicker 的角落:我认为即使在“要求”中也可能存在一些小问题。该规范不使用首选的"MUST, SHOULD, MAY" 措辞,使其有点开放。我将“原因”更多地阅读为实施说明 - 不是要求。再说一次,我还没有阅读整个规范,所以也许他们对这些术语的定义更多或在其他地方更明确。
【讨论】:
不可能在所有序列中都正确支持;许多只是一次(网络流等)。如果你不能一直依赖它,它就毫无用处,因为抽象被破坏了。当然你可以有一个IResettableEnumerator,但是IEnumerator 上的Reset() 没有
工作。坦率地说,这是一个错误(IMO)。
我怀疑它也会使迭代器块甚至更加复杂(它们目前是编译器中最复杂的两个部分之一;我不记得哪个是“顶部”;它们,或匿名方法/捕获的变量)。
【讨论】:
IEnumerator.Reset 在 .NET 1.0 中存在的唯一原因是它可以包装像 IEnumVARIANT 这样的 COM 枚举器,它通常具有 Reset(这可能是优化)。
这是 MSDN 所说的
为 COM 提供了 Reset 方法 互操作性。它不 必然需要实施; 相反,实施者可以简单地 抛出 NotSupportedException。
http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.reset.aspx>MSDN IEnumerator..::.Reset 方法
没有说必须,只是说可以。
编辑: 然而,正如 Marc 所指出的,C# 2.0 规范存在差异
22.2 枚举器对象
请注意,枚举器对象不 支持 IEnumerator.Reset 方法。 调用此方法导致 System.NotSupportedException 为 扔了。
【讨论】: