迭代/枚举列表的一部分?

时间:2015-06-05 10:27:29

标签: c# collections enumeration

有没有办法记住一个普查员的位置? 我想记住枚举的位置,以便我可以将它重置到当前位置之前。我不想回到开头所以.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);

3 个答案:

答案 0 :(得分:1)

由于您已经拥有List<>,为什么不维护索引器/计数器,然后使用IEnumerable Skip()扩展方法(可能将其与Take()结合后跟{{3 }})。

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

答案 1 :(得分:0)

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

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

var pos = 2;  // this is the position

richTextBoxOutput.AppendText(list[pos]); 

您可以随时重置:

pos = (desired position);

答案 2 :(得分:0)

  

有没有办法记住枚举器的位置?

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

在这种情况下,枚举器被实现为一个可变的struct,这是一种性能优化,人们在产生这种&#34;冻结位置时会经常遇到这种情况。在他们想要它的情况下的行为。 (如果你曾经写过包含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;

现在,根据此i定义了tstruct,并从一个复制到另一个复制了struct,而不仅仅是对框struct的引用{1}}。

这对所有调查员都不起作用,因此在编写自己的调查员时,不是故意让它可用的最好方法(如果你需要这样做,你最好添加一些对Clone()而不是Snapshot()的枚举数排序classstruct方法,但它适用于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);
  }
}

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