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

Effective C# 原則 11:優先使用 foreach 迴圈

     編輯:關於C#

foreach 不只是語法糖,編譯器會根據集合實際型別產生最優迭代 IL。對陣列避免裝箱、對多維陣列自動處理邊界、對介面型別自動轉型、甚至自動處理 IDisposable 列舉器。取代 for、while、do-while,寫更少、更快、更穩健的程式碼。

效能比較:三種迴圈

int[] foo = new int[100];
// 1. foreach - 最佳(C# 1.1+)
foreach (int i in foo) Console.WriteLine(i);

// 2. for 使用 Length - 次佳
for (int i = 0; i < foo.Length; i++) Console.WriteLine(foo[i]);

// 3. 提取 Length 到區域變數 - 最差!
int len = foo.Length;
for (int i = 0; i < len; i++) Console.WriteLine(foo[i]);

第 3 種阻礙 JIT 邊界檢查提升:執行期仍對每次迭代檢查 foo.Length,反而產生雙重邊界檢查。foreach 與第 2 種讓 JIT 證明索引安全,移除邊界檢查。

foreach 避免裝箱(陣列)

早期 C# 1.0 foreach 透過 IEnumerator 導致裝箱。現代編譯器對陣列產生索引式迴圈 IL,零裝箱:

// 產生 IL 等同於:
for (int i = 0; i < foo.Length; i++) Console.WriteLine(foo[i]);

多維陣列與非零下界

// 二維棋盤
private Square[,] _board = new Square[8, 8];
// 手寫巢狀 for 需知維度與下界
foreach (Square sq in _board) sq.PaintSquare(); // 自動處理所有維度

// 非零下界陣列(罕見但合法)
var arr = Array.CreateInstance(typeof(int), new[]{5}, new[]{1}); // 索引 1~5
foreach (int v in arr) Console.WriteLine(v); // 正確迭代

重構彈性:集合型別變更不動程式碼

int[] foo = new int[100];
// 後來改為 ArrayList
ArrayList foo = new ArrayList(100);
// for 迴圈全壞:Length→Count、foo[i] 回傳 object 需轉型
// foreach 完全不動:編譯器自動產生正確 IL

自訂型別支援 foreach

實作任一介面即可:

  • IEnumerable(GetEnumerator())
  • IEnumerator
  • 公開 GetEnumerator() 回傳 IEnumerator

資源管理加分:自動處理 IDisposable 列舉器

// 編譯器產生等效碼:
IEnumerator it = foo.GetEnumerator();
using (IDisposable d = it as IDisposable)
{
    while (it.MoveNext())
    {
        int elem = (int)it.Current;
        // ...
    }
}

列舉器實作 IDisposable 時自動包裝 using,確保資源釋放。

總結

foreach:最少程式碼、最佳效能、正確處理邊界/轉型/資源、重構最彈性。迭代集合的首選,無例外。

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