從這兩個接口的用詞選擇上,也可以看出其不同:
a) IEnumerable是一個聲明式的接口,聲明實作該接口的類是可枚舉。
b) IEnumerator是一個實作式的接口,IEnumerator對象說明如何實作枚舉器。
Foreach語句隐式調用集合的無參GetEnumerator方法(不論集合是否有實作IEnumerable接口,但隻要有無參GetEnumerator方法并傳回IEnumerator就可周遊)。
集合類為什麼不直接實作IEnumerable和IEnumerator接口?
這樣是為了提高并發性。Eg:一個周遊機制隻有一個Current,一旦并發就會出錯。然而“将周遊機制與集合分離開來”如果要實作同時周遊同一個集合,隻需由集合IEnumerable.GetEnumerator() 傳回一個新的包含周遊機制(IEnumerator)的類執行個體即可。

01:foreach在數組集合的周遊時會被經常用到,例如
使用foreach做周遊确實很友善,然而并不是每一種類型都能使用foreach進行周遊操作,隻有實作了IEnumerable接口的類(也叫做可枚舉類型)才能進行foreach的周遊操作,集合和數組已經實作了這個接口,是以能進行foreach的周遊操作
02:
foreach是對集合進行周遊,而集合都繼承Array類
foreach結構設計用來和可枚舉類型一起使用,隻要給它的周遊對象是可枚舉類型
隻有實作了IEnumerable接口的類(也叫做可枚舉類型)才能進行foreach的周遊操作,集合和數組已經實作了這個接口,是以能進行foreach的周遊操作
集合繼承IEnumerable這個接口,而IEnumerable的 IEnumerator GetEnumerator()方法 可以獲得一個可用于循環通路集合的 對象
List<string> list = new List<string>() { "252", "哈哈哈", "25256", "春天裡的花朵" };
Console.WriteLine(list.GetType().Name);
IEnumerator listEnumerator = list.GetEnumerator();
while (listEnumerator.MoveNext())
{
Console.WriteLine(listEnumerator.Current);
}
listEnumerator.Reset();
namespace System.Collections
{
//
// 摘要:
// 公開枚舉數,該枚舉數支援在非泛型集合上進行簡單疊代。 若要浏覽此類型的.NET Framework 源代碼,請參閱Reference Source。
[ComVisible(true)]
[Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")]
public interface IEnumerable
{
//
// 摘要:
// 傳回循環通路集合的枚舉數。
//
// 傳回結果:
// 一個可用于循環通路集合的 System.Collections.IEnumerator 對象。
[DispId(-4)]
IEnumerator GetEnumerator();
}
}
//枚舉器内部的方法
namespace System.Collections
{
//
// 摘要:
// 支援對非泛型集合的簡單疊代。
[ComVisible(true)]
[Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")]
public interface IEnumerator
{
//
// 摘要:
// 擷取集合中位于枚舉數目前位置的元素。
//
// 傳回結果:
// 集合中位于枚舉數目前位置的元素。
object Current { get; }
//
// 摘要:
// 将枚舉數推進到集合的下一個元素。
//
// 傳回結果:
// 如果枚舉數已成功地推進到下一個元素,則為 true;如果枚舉數傳遞到集合的末尾,則為 false。
//
// 異常:
// T:System.InvalidOperationException:
// 建立枚舉器後,已修改該集合。
bool MoveNext();
//
// 摘要:
// 将枚舉數設定為其初始位置,該位置位于集合中第一個元素之前。
//
// 異常:
// T:System.InvalidOperationException:
// 建立枚舉器後,已修改該集合。
void Reset();
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace 枚舉器和疊代器
{
class Program
{
static void Main(string[] args)
{
MyClass myClass=new MyClass();
while (myClass.MoveNext())
{
Console.WriteLine(myClass.Current);
}
myClass.Reset();
IEnumerator iEnumerator=myClass.GetEnumerator();
while (iEnumerator.MoveNext())
{
Console.WriteLine(iEnumerator.Current);
}
myClass.Reset();
foreach (string item in myClass.Names)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
//可枚舉的類型可以被枚舉周遊
class MyClass: IEnumerator,IEnumerable
{
public string[] Names { get; set;}
public MyClass()
{
Names = new string[] {"22", "就", "333"};
}
private int postion = -1;
//枚舉器的方法
public object Current
{
get
{
if (postion>=0&&postion<Names.Length)
{
return Names[postion];
}
return null;
}
}
public bool MoveNext()
{
if (postion<Names.Length)
{
postion++;
return true;
}
else
{
return false;
}
}
public void Reset()
{
postion = -1;
}
//擷取枚舉器
public IEnumerator GetEnumerator()
{
return new MyClass();
}
}
}
namespace 疊代器
{
class Program
{
static void Main(string[] args)
{
MyClass myClass=new MyClass();
foreach (var item in myClass)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
public class MyClass : IEnumerable
{
public string[] Names { get; set; }
public MyClass()
{
Names = new string[] { "22", "就", "333" };
}
public IEnumerator GetEnumerator()
{
for (int i = 0; i < Names.Length; i++)
{
yield return Names[i];
}
}
}
}