迭代器與foreach
在C#開發時,迭代器使用通常會搭配foreach陳述式來遍歷集合的內容,對比其他迴圈語法如while、for需要自行判斷迴圈結尾,foreach在執行上當遍歷完整個集合後即完成迴圈。
foreach (var item in List)
{
//item DoSomething...
}
//搭配LINQ條件查詢列表中Num大於100的項目
foreach (var item in List.Where(x => x.Num > 100))
{
//item DoSomething...
}
C#的集合物件都有支援迭代器的功能,搭配上LINQ條件式幾乎可以做到多數的查詢條件,但如果要開發功能的業務邏輯較複雜,需要自行實作迭代器,這時候yield return就可以派上用場。
Yeild return
在執行時foreach一次只會回傳一個項目,當執行到yield return時會回傳第一個char(H),並輸出到Console後,才會繼續執行下一個yield return。
可以嘗試在程式中下中斷點,可以觀察到程式會在兩個地方反覆運算,當執行yield return後,馬上跳出去執行Console.Write(),然後再跳回來。
//一個簡單的yield return範例
public IEnumerable Hello()
{
yield return 'H';
yield return 'e';
yield return 'l';
yield return 'l';
yield return 'o';
}
foreach (char i in Hello())
{
Console.Write(i);
}
// OUTPUT: Hello
這有什麼好處?感覺程式碼變更複雜了。
但從上面的例子發現,使用yield return後可以把查詢的動作與查詢後的處理動作分開,但又能結合使用。
舉個例子,有個讀取圖檔的迴圈,但讀圖後的動作有好幾種,可能是把圖片顯示到螢幕上,或是把圖片縮小後再儲存到其他地方,此時就可以共用一個迭代器。
public IEnumerable<Image> ReadImageFromFolder(string path)
{
//GetImageListFolder...
foreach (string fileName in Folder)
{
yield return Image.FromFile(fileName );
}
}
foreach (Image img in ReadImageFromFolder(@"your folder"))
{
//Scale image...
//Then Save...
}
從上方案例可以理解,好處是節省記憶體的占用,當讀取一張圖後會立即執行處理並釋放掉。不會需要一口氣讀取整個資料夾的圖片,然後一張一張執行。
如果用在資料顯示也有一樣好處,當我讀取一筆資料後,立即顯示到畫面上,就不會看到惱人的轉圈圈了。
結論
總結yield return好處,大概有這幾項
- 查詢動作與處理動作分離,但又能結合使用節省記憶體
- 可以立即回應,當遍歷產生結果立即回傳,可以一邊查詢一邊處理
發佈留言