首先先来了解一下这两个接口的含义,从名字常来看,IEnumerator是枚举器的意思,IEnumerable是可枚举的意思。接着看源码:程序员
public interface IEnumerable
{
// Interfaces are not serializable
// Returns an IEnumerator for this enumerable Object. The enumerator provides
// a simple way to access all the contents of a collection.
[Pure]
[DispId(-4)]
IEnumerator GetEnumerator();
}
复制代码
public interface IEnumerator
{
// Interfaces are not serializable
// Advances the enumerator to the next element of the enumeration and
// returns a boolean indicating whether an element is available. Upon
// creation, an enumerator is conceptually positioned before the first
// element of the enumeration, and the first call to MoveNext
// brings the first element of the enumeration into view.
//
bool MoveNext();
// Returns the current element of the enumeration. The returned value is
// undefined before the first call to MoveNext and following a
// call to MoveNext that returned false. Multiple calls to
// GetCurrent with no intervening calls to MoveNext
// will return the same object.
//
Object Current {
get;
}
// Resets the enumerator to the beginning of the enumeration, starting over.
// The preferred behavior for Reset is to return the exact same enumeration.
// This means if you modify the underlying collection then call Reset, your
// IEnumerator will be invalid, just as it would have been if you had called
// MoveNext or Current.
//
void Reset();
}
复制代码
IEnumerable中只有一个GetEnumerator函数,返回值是IEnumerator类型,因此实现了IEnumerable接口的类能够经过此方法获取一个IEnumerator枚举器,并经过此枚举器遍历这个类中包含的集合中的元素的功能(好比List,ArrayList,Dictionary等继承了IEnumeratble接口的类)。编程
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SuanFa.IEnumerableInterface
{
class InheritIEnumerable : IEnumerable
{
public int[] array = new int[] { 1, 3, 4 };
static void Main()
{
InheritIEnumerable ii = new InheritIEnumerable();
Console.WriteLine("foreach执行结果:");
foreach (int i in ii)
{
Console.WriteLine("i=" + i);
}
}
/// <summary>
/// 返回IEnumerator类型的对象
/// </summary>
/// <returns></returns>
public IEnumerator GetEnumerator()
{
Console.WriteLine("获取枚举器");
return new InheritIEnumerator(array);
}
}
public class InheritIEnumerator : IEnumerator
{
int[] array;
int pos = -1;
public InheritIEnumerator(int []array)
{
this.array = array;
}
public object Current
{
get
{
Console.WriteLine("获取Current");
if (pos<array.Length)
{
return array[pos];
}
else
{
throw new InvalidOperationException();
}
}
}
public bool MoveNext()
{
if (pos<array.Length-1)
{
Console.WriteLine("MoveNext true");
pos++;
return true;
}
else
{
Console.WriteLine("MoveNext false");
return false;
}
}
public void Reset()
{
pos = -1;
}
}
}
复制代码
经过输出结果,能够发现,foreach在运行时会先调用InheritIEnumerable的GetIEnumerator函数获取一个InheritIEnumerator实例(枚举器实例),以后经过循环调用InheritIEnumerator的MoveNext函数,pos后移,更新Current属性,而后返回Current属性,直到MoveNext返回false。 总结一下:框架
这些就是IEnumerable,IEnumerator的基本工做原理。 因此foreach就至关于一下代码:ide
IEnumerable ieable = new InheritIEnumerable();
IEnumerator ie = ieable.GetEnumerator();
while (ie.MoveNext())
{
Console.WriteLine(ie.Current);
}
复制代码
class YieldFunctions
{
public static IEnumerable<int> getNums()
{
yield return 1;
yield return 0;
yield return 3;
yield break;
yield return 5;
}
public static void Main()
{
foreach (int i in getNums())
{
Console.WriteLine(i);
}
}
}
复制代码
先看一下YieldFunctions类的IL代码的总体框架,主要有三部分:getNums生成的IL代码,新生成的getNums类的IL代码,Main方法的IL代码。 函数
再而后能够看一下MoveNext代码: this
用yield来进行迭代的真实流程就是:spa