原文: [原譯]實作IEnumerable接口&了解yield關鍵字 著作權聲明:本文由 http://leaver.me
翻譯,歡迎轉載分享。請尊重作者勞動,轉載時保留該聲明和作者部落格連結,謝謝!
本文讨論題目的内容。然後讨論IEnumerable接口如何使得foreach語句可以使用。之後會展示如果實作自定義的集合類,該集合類實作了IEnumerable接口。Yield關鍵字和周遊集合後面也讨論。
背景
一使用集合。就發現周遊集合就跟着來了。周遊集合最好的方式是實作疊代器模式-
Understanding and Implementing the Iterator Pattern in C# and C++(這篇文章我過幾天翻譯一下) ,C#提供foreach來以一種優雅的方式周遊
隻要集合實作了IEnumerable 接口就可以用foreach來周遊。
使用代碼
首先先看一下内置的集合類如何使用foreach來周遊的。ArrayList實作了IEnumerable 接口。我們看一下
// 看一下實作了IEnumerable 接口的集合如何周遊
ArrayList list = new ArrayList();
list.Add("1");
list.Add(2);
list.Add("3");
list.Add('4');
foreach (object s in list)
{
Console.WriteLine(s);
}
周遊泛型集合類
Arraylist 是一個通用集合類,周遊泛型集合類也可以。因為這些泛型集合類實作了IEnumerable<T>接口,看一下吧。
// 周遊實作了IEnumerable<T>接口的泛型類
List<string> listOfStrings = new List<string>();
listOfStrings.Add("one");
listOfStrings.Add("two");
listOfStrings.Add("three");
listOfStrings.Add("four");
foreach (string s in listOfStrings)
{
Console.WriteLine(s);
}
發現了吧。我們自定義的集合類或是泛型集合類應該實作IEnumerable和IEnumerable<T>接口。這樣就可以周遊了。
了解yield關鍵字
在寫個實作接口的例子之前,先了解一下yield關鍵字,yield會記錄集合位置。當從一個函數傳回一個值的時候,yield可以用。
如下的普通的方法。不論調用多少次,都隻會傳回一個return
static int SimpleReturn()
{
return 1;
return 2;
return 3;
}
static void Main(string[] args)
{
// 看看
Console.WriteLine(SimpleReturn());
Console.WriteLine(SimpleReturn());
Console.WriteLine(SimpleReturn());
Console.WriteLine(SimpleReturn());
}
原因就是普通的return語句不保留函數的傳回狀态。每一次都是新的調用。然後傳回第一個值。
但是使用下面的語句替換後就不一樣。當函數第二次調用的時候。會從上次傳回的地方繼續調用
static IEnumerable<int> YieldReturn()
{
yield return 1;
yield return 2;
yield return 3;
}
static void Main(string[] args)
{
// 看看yield return的效果
foreach (int i in YieldReturn())
{
Console.WriteLine(i);
}
}
顯然傳回1,2,3,唯一要注意的就是函數需要傳回IEnumerable。,然後通過foreach調用。
在自定義的集合類裡實作Ienumerable接口
現在如果我們在我們的自定義集合裡定義一個方法。來疊代所有元素。然後通過使用yield傳回。我們就可以成功了。
好。我們定義MyArrayList 類,實作IEnumerable 接口,該接口就會強制我們實作GetEnumerator 函數。這裡我們就要使用yield了。
class MyArrayList : IEnumerable
{
object[] m_Items = null;
int freeIndex = 0;
public MyArrayList()
{
// 對了友善我直接用數組了,其實應該用連結清單
m_Items = new object[100];
}
public void Add(object item)
{
// 考慮添加元素的時候
m_Items[freeIndex] = item;
freeIndex++;
}
// IEnumerable 函數
public IEnumerator GetEnumerator()
{
foreach (object o in m_Items)
{
// 檢查是否到了末尾。數組的話。。。沒寫好
if(o == null)
{
break;
}
// 傳回目前元素。然後前進一步
yield return o;
}
}
}
之後你就可以用foreach周遊了。
static void Main(string[] args)
{
//看看調用部分
MyArrayList myList = new MyArrayList();
myList.Add("1");
myList.Add(2);
myList.Add("3");
myList.Add('4');
foreach (object s in myList)
{
Console.WriteLine(s);
}
}
這個類啊。沒寫好。也不完整。隻要是讓你了解。。模拟一下而已。
自定義泛型類裡實作Ienumerable<T>接口
class MyList<T> : IEnumerable<T>
{
T[] m_Items = null;
int freeIndex = 0;
public MyList()
{
// 為了友善。使用數組
m_Items = new T[100];
}
public void Add(T item)
{
//添加元素
m_Items[freeIndex] = item;
freeIndex++;
}
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
foreach (T t in m_Items)
{
//檢查是否到了末尾。數組的話。。。沒寫好
if (t == null) // 如果T不是一個可空類型。就中斷
{
break;
}
// 傳回目前元素,然後前進一步
yield return t;
}
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
// 此處調用泛型版本
return this.GetEnumerator();
}
#endregion
}
之後就可以使用foreach了。
static void Main(string[] args)
{
// 使用示例
MyList<string> myListOfStrings = new MyList<string>();
myListOfStrings.Add("one");
myListOfStrings.Add("two");
myListOfStrings.Add("three");
myListOfStrings.Add("four");
foreach (string s in myListOfStrings)
{
Console.WriteLine(s);
}
}
源代碼下載下傳
EnumerableDemo.7z原文位址:
A-Beginners-Tutorial-on-Implementing-IEnumerable-I