close
首先, 以ArrayList為例,透過foreach指令來依序讀取內容物
1: ArrayList list = new ArrayList();
2: list.Add("1");
3: list.Add(2);
4: list.Add("3");
5: list.Add('4');
6: foreach(object o in list)
7: {
8: Console.Write($"{o.GetType().ToString()} :");
9: Console.WriteLine(o);
10: }
假設我們有一個簡單的函式如下,希望每次呼叫依序回傳1, 2, 3…
1: static int SimpleReturn()
2: {
3: return 1;
4: return 2;
5: return 3;
6: }
如果用下列方式呼叫SimpleReturn()
1: static void Demo4()
2: {
3: Console.WriteLine(SimpleReturn());
4: Console.WriteLine(SimpleReturn());
5: Console.WriteLine(SimpleReturn());
6: Console.WriteLine(SimpleReturn());
7: }
似乎只會回傳遞一種結果
如果將SimpleReturn修改成YieldReturn()如下
1: static IEnumerable<int> YieldReturn()
2: {
3: yield return 1;
4: yield return 2;
5: yield return 3;
6: }
用下列方式呼叫YieldReturn()
1: static void Demo5()
2: {
3: foreach(int i in YieldReturn())
4: Console.WriteLine(i);
5: }
結果如下,可以依序取出1, 2, 3,…
-------------------------------------------------------------------------------------------------------------------------------
1. MyArrayList 繼承 IEnumerable介面,其中GetEnumerator()需要自行實作。
1: class MyArrayList : IEnumerable
2: {
3: public IEnumerator GetEnumerator()
4: {
5: throw new NotImplementedException();
6: }
7: }
2. 建立MyArrayList 私有變數成員(m_items、index)及創建子
1: class MyArrayList : IEnumerable
2: {
3: // 儲存陣列
4: object[] m_items = null;
5: // 陣列索引
6: int index = 0;
7:
8: /// <summary>
9: /// MyArrayList創建子
10: /// </summary>
11: public MyArrayList()
12: {
13: // For the sake of simplicity lets keep them as arrays
14: // ideally it should be link list
15: m_items = new object[100];
16: }
17: public IEnumerator GetEnumerator()
18: {
19: throw new NotImplementedException();
20: }
21: }
3. 加入public method: Add() 提供物件加入陣列
1: public void Add(object item)
2: {
3: m_items[index] = item;
4: index++;
5: }
4. 重新定義GetEnumerator:
如同前面YieldReturn()例子, 我們希望提供一個method每呼叫一次,可以取得m_items的一個元素,
並且索引值自動移動至下一個元素(yield), 下次呼叫則傳回該索引值所指的元素(return),重複這些動作直到取完為止(o==null)。
1: public IEnumerator GetEnumerator()
2: {
3: foreach(object o in m_items)
4: {
5: // Lets check for end of list (its bad code since we used arrays)
6: if (o==null)
7: {
8: break;
9: }
10: // Return the current element and then on next function call
11: // resume from next element rather than starting all over again;
12: yield return o;
13: }
14: }
綜合1~4程式碼
1: class MyArrayList : IEnumerable
2: {
3: // 儲存陣列
4: object[] m_items = null;
5: // 陣列索引
6: int index = 0;
7:
8: /// <summary>
9: /// MyArrayList創建子
10: /// </summary>
11: public MyArrayList()
12: {
13: // For the sake of simplicity lets keep them as arrays
14: // ideally it should be link list
15: m_items = new object[100];
16: }
17:
18: public void Add(object item)
19: {
20: m_items[index] = item;
21: index++;
22: }
23: public IEnumerator GetEnumerator()
24: {
25: foreach(object o in m_items)
26: {
27: // Lets check for end of list (its bad code since we used arrays)
28: if (o==null)
29: {
30: break;
31: }
32: // Return the current element and then on next function call
33: // resume from next element rather than starting all over again;
34: yield return o;
35: }
36: }
37: }
MyArrayList範例:
1: static void Demo6()
2: {
3: MyArrayList myArrayList = new MyArrayList();
4:
5: myArrayList.Add("1");
6: myArrayList.Add(2);
7: myArrayList.Add("3");
8: myArrayList.Add('4');
9: foreach (object s in myArrayList)
10: {
11: Console.WriteLine(s);
12: }
13: }
接下來,加入泛型: MyList
1: class MyList<T> : IEnumerable<T>
2: {
3: // 儲存陣列
4: T[] m_Items = null;
5: // 陣列索引
6: int index = 0;
7: public MyList()
8: {
9: // For the sake of simplicity lets keep them as arrays
10: // ideally it should be link list
11: m_Items = new T[100];
12: }
13: public void Add(T item)
14: {
15: // Let us only worry about adding the item
16: m_Items[index] = item;
17: index++;
18: }
19:
20: public IEnumerator<T> GetEnumerator()
21: {
22: foreach(T o in m_Items)
23: {
24: // Lets check for end of list (its bad code since we used arrays)
25: if (o==null)
26: {
27: break;
28: }
29: // Return the current element and then on next function call
30: // resume from next element rather than starting all over again;
31: yield return m_Items[index];
32: }
33: }
34:
35: IEnumerator IEnumerable.GetEnumerator()
36: {
37: // Lets call the generic version here
38: return this.GetEnumerator();
39: }
40: }
MyList範例:
1: // Let us first see how we can enumerate an custom MyList<t> class implementing IEnumerable<T>
2: MyList<string> myListOfStrings = new MyList<string>();
3:
4: myListOfStrings.Add("one");
5: myListOfStrings.Add("two");
6: myListOfStrings.Add("three");
7: myListOfStrings.Add("four");
8:
9: foreach (string s in myListOfStrings)
10: {
11: Console.WriteLine(s);
12: }
1. 利用while()搭配yield指令,每次呼叫GetRandIntSub()吐出一個隨機整數值,其格式為IEnumerable<int>
1: private static IEnumerable<int> GetRandIntSub(int range)
2: {
3: while(true)
4: {
5: Random r = new Random();
6: yield return r.Next() % range;
7: }
8: }
2. 再利用foreach去接收IEnumerable<int>的東西
1: private static int GetRandInt()
2: {
3: int range = 10;
4: int output = 0;
5: foreach(int val in GetRandIntSub(range))
6: {
7: output = val;
8: return output;
9: }
10: return output;
11: }
3. 呼叫GetRandInt()
1: private static void Demo8()
2: {
3: IList<int> myList = new List<int>();
4: for (int i = 0; i < 10; i++)
5: {
6: myList.Add(GetRandInt());
7: Console.WriteLine($"length: {myList.Count}");
8: Console.WriteLine($"value: {myList[myList.Count - 1]}");
9: Thread.Sleep(100);
10: }
11: }
結果如下:
參考資料:
1. A Beginner's Tutorial on Implementing IEnumerable Interface and Understanding yield Keyword
全站熱搜