我有一个存储字符串列表的类,我想让这个类在 foreach 语句中可用,所以我找到了这两个接口(interface)并尝试实现它们。
public class GroupCollection : IEnumerable, IEnumerator
{
public List<string> Groups { get; set; }
public int Count { get { return Groups.Count; } }
int position = -1;
}
public IEnumerator GetEnumerator()
{
return (IEnumerator)this;
}
public object Current
{
get
{
try
{
return new Group(Groups[position]);
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}
public bool MoveNext()
{
position++;
return position < Groups.Count;
}
public void Reset()
{
position = 0;
}
我正在遍历 GroupCollection 变量两次:
foreach (GroupCollection.Group in groups) // where groups is a GroupCollection
{
}
foreach (GroupCollection.Group in groups)
{
}
// where Group is a nested class in GroupCollection.
当它在第一个 foreach 时效果很好(此时计数为 1)。我不修改任何东西,当它进入第二个 foreach 时,它不会进入循环。我在 Debug模式下逐行检查代码,发现在第一个 foreach 之后没有调用重置。那么我应该在 foreach 之后手动调用 reset 吗?有没有更好的方法来做到这一点?
最佳答案
I don't modify anything
是的 - 您的 MoveNext()
修改类的状态。这就是为什么不应在同一个类中同时实现 IEnumerable
和 IEnumerator
的原因。 (C# 编译器会处理迭代器 block ,但这是一种特殊情况。)您应该能够调用 GetEnumerator()
两次并获得两个完全独立的迭代器。例如:
foreach (var x in collection)
{
foreach (var y in collection)
{
Console.WriteLine("{0}, {1}", x, y);
}
}
... 应该为您提供集合中所有可能的项目对。但是,仅在迭代器独立时有效。
I went through the code line by line in debugging mode and found out that the reset is not called after the first foreach.
为什么你会期望它?我不相信该规范对 foreach
调用 Reset
有任何说明 - 这是一个很好的工作,因为许多实现并不真正实现它(他们抛出异常)。
基本上,您应该让您的 GetEnumerator()
方法返回一个新对象,该对象在您的数据上保持“游标”的可变状态。请注意,在 C# 中实现迭代器的最简单方法是通常使用迭代器 block (yield return
等)。
我还强烈鼓励您实现通用接口(interface),而不仅仅是非通用接口(interface);这样你的类型就可以更容易地在 LINQ 代码中使用,foreach
语句中的迭代器变量可以适本地隐式键入,等等。
关于c# - 我实现 IEnumerator 和 IEnumerable 的类不会转到 foreach 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29492712/