首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 迭代器進階:yield return、延遲執行與狀態機原理

     編輯:關於C#

yield return 是 C# 2.0 引入的迭代器語法,編譯器將其轉換為實作 IEnumerable/IEnumerator 的**狀態機類別**,實現延遲執行 與 流式處理,是 LINQ to Objects 效能基石。

延遲執行對比


// 立即執行:建立 List 佔用記憶體
IEnumerable Eager()
{
    var list = new List();
    for (int i = 0; i < 20; i++)
    {
        Console.WriteLine($"Eager: {i}");
        if (i > 2) list.Add(i);
    }
    return list;
}

// 延遲執行:逐個產生
IEnumerable Lazy()
{
    for (int i = 0; i < 20; i++)
    {
        Console.WriteLine($"Lazy: {i}");
        if (i > 2) yield return i;
    }
}

執行結果差異


// 僅呼叫方法,不迭代
Eager();  // 輸出 0~19
Lazy();   // 無任何輸出!迭代器尚未啟動

// 迭代消費
foreach (var x in Eager()) Console.WriteLine($"Out: {x}");
// 輸出:0~19 (Eager) 然後 3~19 (Out)

foreach (var x in Lazy()) Console.WriteLine($"Out: {x}");
// 輸出:0 (Lazy) 0 (Out) 1 (Lazy) 1 (Out) 2 (Lazy) 2 (Out) 3 (Lazy) 3 (Out) ...
// 交替產生與消費,記憶體常數級

編譯器生成的狀態機

  • 方法轉換為巢狀類別 <Lazy>d__0 : IEnumerable, IEnumerator, IDisposable。
  • 欄位:<>1__state (狀態:-2=未啟動, -1=結束, 0=啟動中, 1=產生中)、<>2__current (當前值)、<i>5__1 (區域變數 i)。
  • MoveNext() 包含巨大 switch(state),每次呼叫從上一狀態繼續執行至下一 yield return。
  • GetEnumerator() 回傳自身 (或新實例視語境)。

延遲執行的實務價值

  • 記憶體效率:處理大量資料/無限序列不需全量載入。
  • 管線組合:LINQ Where/Select/Take 串聯形成查詢管線,僅在終端操作 (ToList/foreach) 觸發執行。
  • 提早終止:Take(5) 僅迭代 5 次,後續運算完全跳過。
  • 錯誤延遲:建立查詢不拋出例外,執行時才拋出,便於組合。

yield break 與 finally


IEnumerable WithFinally()
{
    try
    {
        for (int i = 0; i < 10; i++)
            if (i == 5) yield break; // 提早結束
            else yield return i;
    }
    finally
    {
        Console.WriteLine("Cleanup"); // 保證執行 (Dispose 時)
    }
}
  • yield break 相當於 state = -1; return false;。
  • finally 區塊在 Dispose() (迭代器結束或 foreach 中斷) 時執行,保證資源釋放。

避坑指南

  • 不要在 yield return 方法中直接回傳 List/陣列 (失去延遲優勢)。
  • 避免在迭代器中修改共享可變狀態 (多執行緒不安全)。
  • 捕獲迴圈變數參見 Lambda 閉包,C# 5.0+ 已修正。
  • 效能敏感熱路徑可考慮手寫結構體迭代器 (如 List.Enumerator) 避免類別分配。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved