List <t> .Enumerator </t>的Reset方法的行为

时间:2014-04-18 08:48:10

标签: c# .net list ienumerator

以下两种方法(一种使用IEnumerator<int>,另一种使用List<int>.Enumerator),即使外观相同也会产生不同的结果。

static void M1()
{
  var list = new List<int>() { 1, 2, 3, 4 };
  IEnumerator<int> iterator = list.GetEnumerator();
  while (iterator.MoveNext())
  {
     Console.Write(iterator.Current);
  }
  iterator.Reset();
  while (iterator.MoveNext())
  {
      Console.Write(iterator.Current);
  }
}
static void M2()
{
  var list = new List<int>() { 1, 2, 3, 4 };
  //Here the iterator will be List<int>.Enumerator (which is a struct)
  var iterator = list.GetEnumerator();
  while (iterator.MoveNext())
  {
     Console.Write(iterator.Current);
  }
  //This will not work, as Reset method was implemented explicitly
  //iterator.Reset();

  //So casting it to IEnumerator is required
  //which will lead to boxing and other issues of struct and interface
  ((IEnumerator<int>)iterator).Reset();

  //Following loop will NOT work
  while (iterator.MoveNext())
  {
    Console.Write(iterator.Current);
  }
}

有几个问题可以清楚地解释这种行为,您可以查看hereherehere

我仍然有两个疑问

  1. 为什么List.Enumerator不会抛出&#34; NotSupportedException&#34;重置?
  2. 为什么要显式实现重置,而不是像MoveNext和Current那样隐式实现?

2 个答案:

答案 0 :(得分:7)

  

为什么List.Enumerator不会抛出&#34; NotSupportedException&#34;重置?

因为微软没有时间机器可以预见5年后会发生什么。类型推断背后的强大推动力是Linq,它在20世纪90年代后期的路线图上并没有出现,当时仿制药首次被开发出来。如果没有它,拳击问题就不是问题。

  

为什么要显式实现重置,而不是像MoveNext和Current那样隐式实现?

因为您无法继承接口方法,所以只能隐藏它。 IEnumerator有一个Reset()方法是另一个时间机器问题,这是在1995年COM Automation设计时决定的。选择和后果之间差距大约相隔5年:) .NET 已经COM iterators和.NET迭代器之间提供了一个不错的映射,以便有机会被采用。

从链接可以看出,COM迭代器中的另一个功能是克隆。这是ICloneable接口背后的推动力,这是.NET中另一个非常麻烦的界面。在他们的通用兄弟中实施这个太麻烦了,只有非通用的集合枚举器才能实现它。

微软的工作很艰巨,每一项设计决定都是他们必须永远忍受的。我们更容易,我们可以简单地不使用重置:)

答案 1 :(得分:2)

  

为什么List.Enumerator不会为重置?

抛出“NotSupportedException”

为什么要这样? List<T>是一种实现Reset的微不足道的类型,为什么不实现呢?

  

为什么要显式实现重置,而不是像MoveNext和Current那样隐式实现?

我认为这是因为Reset现在通常被认为是一个错误。但它确实存在,所以它必须以某种方式实现。所以使用显式接口实现隐藏它是有道理的,它说“你可能不应该使用它”。