首頁 » C#學習 » 迭代器(Iterator)搭配yield return

迭代器(Iterator)搭配yield return

作者:

分類:

迭代器與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好處,大概有這幾項

  • 查詢動作與處理動作分離,但又能結合使用節省記憶體
  • 可以立即回應,當遍歷產生結果立即回傳,可以一邊查詢一邊處理

參考資料

「cian」的個人頭像

留言

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *