为什么Enumerator类上的Reset()方法必须抛出NotSupportedException()?

时间:2009-09-23 19:43:22

标签: c# .net

从我在http://csharpindepth.com/Articles/Chapter6/IteratorBlockImplementation.aspx上看到的内容和Jon Skeet的文章来看,c#规范本身就是这样说的。会是什么原因?

3 个答案:

答案 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为   抛出。