首先先來了解一下這兩個接口的含義,從名字常來看,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代碼。 函數
接下來查看一下getNums方法生成的IL代碼,能夠返如今該方法中,建立了一個getNums類的對象,並將其做爲返回值。 而後看一下生成的新的類getNums的代碼:再而後能夠看一下MoveNext代碼: this
用yield來進行迭代的真實流程就是:spa