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

C# 迭代器深度解析:從迭代器模式到 yield 關鍵字的演進

     編輯:關於C#

前言:為什麼需要迭代器?

在日常開發中,我們經常面對各種集合類型:List、Hashtable、ArrayList 等。它們內部存儲結構各異,若客戶代碼直接依賴具體集合的實現細節(如下標訪問、鍵值遍歷),一旦需要替換集合類型,代碼將面臨大規模修改,違反開閉原則。

迭代器模式的核心目的在於:提供一種統一的方式順序訪問集合元素,而無需暴露集合的內部表示。

手動實現迭代器模式

我們可以定義兩個介面:ICollection 負責集合操作,Iterator 負責遍歷邏輯。每種具體集合(如 List)對應一個專屬迭代器(ListIterator)。

public interface ICollection {
    int Count { get; }
    Iterator GetIterator();
}

public interface Iterator {
    bool MoveNext();
    object Current { get; }
}

public class List : ICollection {
    private object[] items = new object[10];
    public Iterator GetIterator() => new ListIterator(this);
    // ... 索引器、Count 實現
}

public class ListIterator : Iterator {
    private int index = 0;
    private ICollection list;
    public ListIterator(ICollection list) { this.list = list; }
    public bool MoveNext() { /* 邏輯 */ }
    public object Current { get { /* 邏輯 */ } }
}

客戶代碼僅依賴介面:

ICollection list = new List();
Iterator iterator = list.GetIterator();
while (iterator.MoveNext()) {
    object current = iterator.Current;
    // 處理元素
}

此時若將 List 換為 Hashtable,只需提供對應的 HashtableIterator,客戶代碼完全不變。

.NET 框架內建支援:IEnumerable 與 IEnumerator

微軟在 .NET 基礎類庫中將此模式標準化:

  • IEnumerable:對應 ICollection,唯一方法 GetEnumerator() 返回迭代器。
  • IEnumerator:對應 Iterator,包含 MoveNext()、Current、Reset()。

所有集合類(ArrayList、List<T>、Dictionary<TKey,TValue> 等)均實現 IEnumerable,使得統一遍歷成為可能:

IEnumerator enumerator = list.GetEnumerator();
while (enumerator.MoveNext()) {
    object item = enumerator.Current;
}

foreach 的語法糖與 IL 解析

手寫 while 迴圈繁瑣且易出錯,C# 提供 foreach 關鍵字。編譯器會將其展開為標準的 try/finally 模式:

  1. 調用 GetEnumerator() 獲取迭代器。
  2. 在 try 區塊中循環調用 MoveNext() 並讀取 Current。
  3. 在 finally 區塊中檢查迭代器是否實現 IDisposable,若是則調用 Dispose() 釋放非托管資源。

關鍵差異: 手寫 while 迴圈若拋出異常,迭代器可能不會被正確釋放;foreach 保證資源釋放,更安全穩健。

foreach IL 代碼結構

yield 關鍵字:迭代器塊的語法糖

C# 2.0 引入 yield return / yield break,讓開發者無需手寫 IEnumerator 實現類,即可輕鬆創建自定義迭代器:

public IEnumerable<int> GetNumbers() {
    yield return 1;
    yield return 2;
    yield return 3;
}
// 編譯器自動生成實現 IEnumerable/IEnumerator 的狀態機類

yield 的「奇怪」特性在於:方法執行會在每次 yield return 處暫停,下次 MoveNext() 時從原處繼續。這種惰性求值特性是 LINQ 延遲執行的基石。

總結

從手寫迭代器模式,到 .NET 標準化 IEnumerable/IEnumerator,再到 foreach 語法糖與 yield 迭代器塊,C# 的迭代機制經歷了「模式 → 框架 → 語法 → 編譯器生成」的演進。理解這一脈絡,不僅能寫出更優雅的代碼,更能深入掌握 LINQ 等高級特性的底層原理。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved