列表的重置方法的行为.枚举 数

本文关键字:枚举 方法 列表 | 更新日期: 2023-09-27 17:58:49

以下两种方法(一种使用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);
  }
}

有几个问题可以清楚地解释这种行为,你可以在这里、这里和这里检查它们。

我还有以下两个疑问

  1. 为什么 List.Enumerator 不会抛出"NotSupportedException"进行重置?
  2. 为什么 Reset 是显式实现的,而不是像 MoveNext 和 Current 那样隐式实现的?

列表<T>的重置方法的行为.枚举 数

为什么 List.Enumerator 不会抛出"NotSupportedException"进行重置?

因为Microsoft没有时间机器来预测5年后会发生什么。 类型推断背后的强大推动力是 Linq,只是在 1990 年代后期首次开发泛型时,它还没有出现在路线图上。 没有它,拳击问题就不是问题。

为什么 Reset 是显式实现的,而不是像 MoveNext 和 Current 那样隐式实现的?

由于无法取消继承接口方法,因此只能隐藏它。 IEnumerator 有一个 Reset(( 方法是另一个时间机器问题,这是在 1995 年设计 COM Automation 时决定的。 选择和后果之间大约还有5年的差距:) .NET 必须在 COM 迭代器和 .NET 迭代器之间提供一个体面的映射,以便有机会被采用。

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

Microsoft的工作很艰难,每一个设计决策都是他们必须永远忍受的。 我们的要容易得多,我们根本无法使用重置:)

为什么 List.Enumerator 不会抛出"NotSupportedException"进行重置?

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

为什么 Reset 是显式实现的,而不是像 MoveNext 和 Current 那样隐式实现的?

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