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