C# yield 執行流程
開始
迭代器狀態機
呼叫 MoveNext()
yield return 值
保存目前狀態
# 為什麼需要 yield?
在C#開發中,我們經常需要處理大量數據的集合。傳統的做法是先將所有數據載入到記憶體中,再進行處理。但這種方式在處理大量數據時會佔用大量記憶體,影響程式效能。
這時候就需要用到 yield 關鍵字。yield 可以讓我們實現延遲執行(Lazy Evaluation),也就是說,只有在真正需要數據時才進行處理,大大節省記憶體使用。
yield 基本用法 讓我們從一個簡單的例子開始:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public static IEnumerable<int > Fibonacci (int count ){ int current = 0 ; int next = 1 ; for (int i = 0 ; i < count; i++) { yield return current; int temp = next; next = current + next; current = temp; } } foreach (int number in Fibonacci (10 )){ Console.WriteLine(number); }
在這個例子中,yield return 會在每次迭代時返回一個數字,而不是一次性計算出所有數字。這意味著即使我們要產生一百萬個費波那契數,程式也不會一次佔用大量記憶體。
yield break 的使用 有時候我們需要在某個條件下提前結束迭代,這時可以使用 yield break:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public static IEnumerable<string > ReadUntilEmptyLine (string filePath ){ using (StreamReader reader = new StreamReader(filePath)) { string line; while ((line = reader.ReadLine()) != null ) { if (string .IsNullOrEmpty(line)) { yield break ; } yield return line; } } }
yield 的應用場景
大文件處理
數據庫分頁查詢
自定義集合類別
無限序列生成
以數據庫分頁查詢為例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public static IEnumerable<User> GetUsersByPage (int pageSize ){ int offset = 0 ; while (true ) { var users = dbContext.Users .Skip(offset) .Take(pageSize) .ToList(); if (!users.Any()) { yield break ; } foreach (var user in users) { yield return user; } offset += pageSize; } }
最佳實踐與注意事項
yield 方法內不能使用 try-catch-finally
yield return 只能在方法內直接使用
yield 方法的返回類型必須是 IEnumerable 或相關介面
避免在 yield return 中執行耗時操作
結論 yield 是C#中非常強大的功能,能夠幫助我們編寫更高效的程式碼。通過延遲執行的特性,我們可以更好地控制記憶體使用,提升程式效能。
要進一步了解 yield 的使用,可以參考: