著作權宣告:本文由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); } }
原始碼下載
原文地址: A-Beginners-Tutorial-on-Implementing-IEnumerable-I
著作權宣告:本文由http://leaver.me 翻譯,歡迎轉載分享。請尊重作者勞動,轉載時保留該宣告和作者部落格連結,謝謝!