Iterate/enumerate 超过列表的一部分?

Iterate/enumerate over part of a list?

有没有办法记住枚举数的位置? 我想记住枚举的位置,以便我可以将它重置为当前位置之前的位置。我不想回到开始,所以 .reset() 没有帮助。 顺便说一句,是否可以让枚举器从 2. 位置开始?

List<string> list = new List<string>(new string[] { "a", "b", "c" });
IEnumerator<string> i = list.GetEnumerator();
i.MoveNext(); richTextBoxOutput.AppendText(i.Current);
IEnumerator<string> t = i; // how do I make a real copy i?
i.MoveNext(); richTextBoxOutput.AppendText(i.Current);
i = t;
i.MoveNext(); richTextBoxOutput.AppendText(i.Current);

您确定需要 IEnumerator 实例吗?为什么不枚举使用索引并将其存储在您自己的变量中?

var list = new List<string>(new { "a", "b", "c" });

var pos = 2;  // this is the position

richTextBoxOutput.AppendText(list[pos]); 

您可以随时重置:

pos = (desired position);

因为你已经有一个 List<> 为什么不维护一个 indexer/counter 然后使用 IEnumerable Skip() extension method (and possibly combine that with Take() followed by ForEach()).

一些可能有用的进一步信息:

Is there a way to remember the position of an enumerator?

有时。这取决于枚举器的实现方式。

在这种情况下,枚举器被实现为一个可变的 struct,这是一种性能优化,人们更经常 运行 在它产生这种 "freeze position" 行为的情况下想要它。 (如果你曾经写过一个通用的 class 来包装 IEnumerable<T> 的实现,那么要么将该引用作为接口类型而不是类型本身,要么就不要它 readonly即使它看起来应该是这样,但如果你这样做了,你最终可能会永久冻结这样一个结构枚举器。

只需更改您的代码,而不是:

IEnumerator<string> i = list.GetEnumerator();
…
IEnumerator<string> t = i;

你有:

List<string>.Enumerator i = list.GetEnumerator();
…
List<string>.Enumerator t = i;

或者简单地说:

var i = list.GetEnumerator();
…
var t = i;

现在您根据此 struct 定义了 it 并且从一个复制到另一个复制了 struct 而不仅仅是对盒装 struct.

这不适用于所有枚举器,就此而言,在编写您自己的枚举器时故意使其可用并不是最好的方法(如果您需要这样做,您最好添加某种Clone()Snapshot() 枚举器的方法是 class 而不是 struct),但它适用于 List<T>.

一个不依赖于这种怪癖的实现的更灵活的解决方案是:

public class SnapshotableListEnumerator<T> : IEnumerator<T>
{
  private readonly IList<T> _list;
  private int _idx;
  private SnapshotableListEnumerator(IList<T> list, int idx)
  {
    _list = list;
    _idx = idx;
  }
  public SnapshotableListEnumerator(IList<T> list)
    : this(list, -1)
  {
  }
  public bool MoveNext()
  {
    // Note that this enumerator doesn't complain about the list
    // changing during enumeration, but we do want to check that
    // a change doesn't push us past the end of the list, rather
    // than caching the size.
    if(_idx >= _list.Count)
      return false;
    ++_idx;
    return true;
  }
  public void Reset()
  {
    _idx = -1;
  }
  public T Current
  {
    get
    {
      if(_idx < 0 || _idx >= _list.Count)
        throw new InvalidOperationException();
      return _list[_idx];
    }
  }
  object IEnumerator.Current
  {
    get { return Current; }
  }
  public void Dispose()
  {
  }
  public SnapshotableListEnumerator<T> Snapshot()
  {
    return new SnapshotableListEnumerator<T>(_list, _idx);
  }
}
public static class SnapshotableListEnumeratorHelper
{
  public static SnapshotableListEnumerator<T> GetSnapshotableEnumerator<T>(this IList<T> list)
  {
    return new SnapshotableListEnumerator<T>(list);
  }
}

现在您可以在 IList<T> 的任何实现上调用 GetSnapshotableEnumerator() 并在您需要枚举中位置的副本时使用其 Snapshot() 方法。