使用foreach循环时,GetEnumerator()方法被调用了多少次?
使用foreach循环时,GetEnumerator()方法被调用了多少次?
下面是我自己创建的自定义类:\n
class B : IEnumerable { int[] data = { 0, 1, 2, 3, 4 }; public IEnumerator GetEnumerator() { Console.WriteLine("被调用"); return new BEnumerator(this); } private class BEnumerator : IEnumerator { private B instance; private int position = -1; public BEnumerator(B inst) { this.instance = inst; } public object Current { get { return instance.data[position]; } } public bool MoveNext() { position++; return (position < instance.data.Length); } public void Reset() { position = -1; } } }
\n如果我们通过foreach进行迭代:\n
B b = new B(); foreach (var item in b) { Console.WriteLine(item); } foreach (var item in b) { Console.WriteLine(item); }
\n输出结果为:\n
被调用 0 1 2 3 4 被调用 0 1 2 3 4
\n我们可以看到,由于使用了两个foreach循环,GetEnumerator()方法被调用了两次,每个foreach循环调用一次,这是可以理解的。\n但是,如果我们将迭代器修改为:\n
public IEnumerator GetEnumerator() { yield return data[0]; yield return data[1]; yield return data[2]; yield return data[3]; yield return data[4]; }
\n很容易看出,为了获取每个值,GetEnumerator()方法将被调用五次。那么,为什么GetEnumerator()有时只被调用一次,有时被调用多次,这是不一致的呢?\nP.S\n我知道使用yield运行代码时,结果是相同的,并且似乎GetEnumerator()只被调用了两次,但是由于yield的特殊性,使得整个方法对于每个foreach循环似乎只被调用一次,但是在后台实际上是需要多次调用的(在这种情况下GetEnumerator()将被调用10次)。
在使用foreach循环时,GetEnumerator()方法被调用了多少次的问题,其原因是yield语句的特殊性。根据微软官方文档中的示例,可以看到在foreach循环的迭代过程中,会调用MoveNext()方法,该方法执行MyIteratorMethod的代码,直到遇到下一个yield return语句。yield return语句不仅确定了元素变量的值,还确定了元素的Current属性。
编译器会为这个方法生成代码,并创建一个实现IEnumerator接口的类来进行枚举操作(类似于你提供的代码)。需要注意的是,编译器会生成许多代码,执行特殊的操作,这些操作是无法手动实现的,这也可以被视为一种不一致性。
对于以下代码:
public IEnumerator GetEnumerator() { yield return data[0]; yield return data[1]; yield return data[2]; yield return data[3]; yield return data[4]; }
编译器会生成如下方法:
[IteratorStateMachine(typeof(d__1))] public IEnumerator GetEnumerator() { d__1 d__ = new d__1(0); d__.<>4__this = this; return d__; }
同时会生成一个类:
[CompilerGenerated] private sealed classd__1 : IEnumerator
需要注意的是,类
总结起来,使用yield关键字时,GetEnumerator()方法只会被调用一次。