星期四, 2月 21, 2008

[.Net]c# Iterator

這裡沒有要解說什麼,下面這段程式是從 c# specification 來的,而程式本來是不能執行的,是的,範例有問題。問題點:
  1. 原本的 IEnumerator<T> GetEnumerator() 應該加上 IEnumerable<T>.,成為 IEnumerator<T> IEnumerable<T>.GetEnumerator()
  2. 少繼承了 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。

沒有留言: