這裡沒有要解說什麼,下面這段程式是從 c# specification 來的,而程式本來是不能執行的,是的,範例有問題。問題點:
- 原本的 IEnumerator<T> GetEnumerator() 應該加上 IEnumerable<T>.,成為 IEnumerator<T> IEnumerable<T>.GetEnumerator()
- 少繼承了 IEnumerable 介面並實做 IEnumerable.GetEnumerator()
我查了很久,才找到問題點,另外還參考 Bertrand Le Roy 的文章,精簡了 IEnumerable.GetEnumerator() 的代碼。
Iterator 就類似 Python/Boo Generator 的概念,目前我認知到最大的好處是,不一定要讓迴圈全部跑完,就可以先傳回一個值去處理。
using System; using System.IO; using System.Collections; using System.Collections.Generic; public class Tree<T>: IEnumerable<T>, IEnumerable { T value; Tree<T> left; Tree<T> right; public Tree(T value, Tree<T> left, Tree<T> right) { this.value = value; this.left = left; this.right = right; } IEnumerator<T> IEnumerable<T>.GetEnumerator() { if (left != null) { foreach (T x in left) yield return x; } yield return value; if (right != null) { foreach (T x in right) yield return x; } } // Yield and generics rock! - Tales from the Evil Empire <http://weblogs.asp.net/bleroy/archive/2004/08/31/223531.aspx> IEnumerator IEnumerable.GetEnumerator() { return (IEnumerator)(((IEnumerable<T>)this).GetEnumerator()); } } public class Program { static Tree<T> MakeTree<T>(T[] items, int left, int right) { if (left > right) return null; int i = (left + right) / 2; return new Tree<T>(items[i], MakeTree(items, left, i - 1), MakeTree(items, i + 1, right)); } static Tree<T> MakeTree<T>(params T[] items) { return MakeTree(items, 0, items.Length - 1); } // The output of the program is: // 1 2 3 4 5 6 7 8 9 // Mon Tue Wed Thu Fri Sat Sun public static void Main() { Tree<int> ints = MakeTree(1, 2, 3, 4, 5, 6, 7, 8, 9); foreach (int i in ints) Console.Write("{0} ", i); Console.WriteLine(); Tree<string> strings = MakeTree( "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"); foreach (string s in strings) Console.Write("{0} ", s); Console.WriteLine(); Console.ReadLine(); } }
額外的收穫是,發現 mono gmcs 編譯出來的代碼比 Microsoft csc 編譯出來的代碼要多出約四百多個 bytes。