C# 2.0 可能討論比較多的是泛型, 其次可能就是迭代器,匿名方法了.
這兩個特性其實有些本質上的不同, 泛型, 是相對1.1微軟在 IL 上面又添加了一些指令來實現.
而迭代器則是在編譯器這個層次去實現的,也就是說C# 2.0 中的迭代器的特性並沒有靠引入IL來實現.
什麼是迭代器呢,我拿一個例子來說明.
比如我們一下一段代碼list 一個特定目錄下面的所有檔案, 代碼可能會這麼寫.
public class C1IterationDemo:IEnumerable,IEnumerator
{
IEnumerable 成員#region IEnumerable 成員
public IEnumerator GetEnumerator()
{
return this;
}
#endregion
IEnumerator 成員#region IEnumerator 成員
int curIndex=-1;
public void Reset()
{
curIndex=-1;
}
public object Current
{
get
{
if(curIndex < this.allFiles.Count)
{
return this.allFiles[curIndex];
}
throw new Exception("f");
}
}
public bool MoveNext()
{
if(this.allFiles.Count==0)
return false;
curIndex+=1;
if(curIndex==this.allFiles.Count)
{
return false;
}
return true;
}
#endregion
private System.Collections.Specialized.StringCollection allFiles=null;
public C1IterationDemo GetFiles(string dirPath)
{
allFiles=new System.Collections.Specialized.StringCollection();
allFiles.Clear();
foreach(string f in System.IO.Directory.GetFiles(dirPath))
{
allFiles.Add(f);
}
return this;
}
}
一下是調用:
C1IterationDemo c=new C1IterationDemo().GetFiles("C:\\WUTemp");
foreach(string s in c)
{
Console.WriteLine(s);
}
其中這裡foreach 就是調用了IEnumerator的movelast, 類似 foreach 這樣的調用方式,一般就是一個迭代器.
如果要你去實作類別似的代碼的話,可能也大通小異, 另外,我們枚舉檔案的時候還沒有考慮子目錄的情況.
類似的代碼我們用C# 2.0 的話就變得很簡單很簡單,我一併考慮了子目錄的情況.
public class FileUtility
{
public static IEnumerable<String> GetFiles(string dir)
{
foreach(String file in System.IO.Directory.GetFiles(dir))
{
yield return file;
}
foreach (string dir1 in System.IO.Directory.GetDirectories(dir))
{
foreach(string ff in System.IO.Directory.GetFiles(dir1))
{
yield return ff;
}
}
}
}
調用
foreach(String f in FileUtility.GetFiles("c:\\wutemp"))
{
System.Diagnostics.Debug.WriteLine(f);
}
對比一下代碼,後面的代碼可能有幾個特點:
1。代碼很簡潔。其實這裡多了一個yield return 語句,由於yield return 並不對應多餘的il指令。所以編譯器就會在編譯的時候,產生一個實現Ienumator介面的類.並且自動維護該類的狀態.比如movenext,
2. 使用yield return 很容易實現遞迴調用中的迭代器. 如果以上的問題,不使用yield return的話,可想而知.要麼你先把所有的結果暫時放到一個對象集合中. 可是這樣就以為著在迭代之前一定要計算號. 要麼可能你的movenext 就相當的複雜了. .NET 編譯產生的程式碼其實利用了state machine. 代碼量也很大.
類似迭代的調用,比如二叉樹遍曆 用yield return 就很方便了.另外還有常說的pipeline模式也很方便了.
可是yield return 還是有一些缺陷.
比如如果GetFiles 有一個參數是ref 或者 out, 那這個state machine就很難去維護狀態了. 事實上,yield return那是不支援方法帶有ref或者out參數的情況.
more information,please refer:
Iterations with c2:
http://www.theserverside.net/articles/showarticle.tss?id=IteratorsWithC2
使用匿名方法、迭代程式和局部類來建立優雅的代碼:
http://www.microsoft.com/china/msdn/library/langtool/vcsharp/CreElegCodAnymMeth.mspx