[C#]Effective C# 條款十一: 優先採用foreach迴圈

  • 57303
  • 0
  • C#
  • 2011-02-09

[C#]Effective C# 條款十一: 優先採用foreach迴圈

C#中的foreach迴圈並不僅僅是do…while或是for迴圈的變形。它會與.NET框架中的集合接口做緊密的結合,在編譯時為我們最佳化程式碼。除此之外foreach使用上也具備較高的相容性。

 

讓我們先來看三種迴圈的寫法:

1.foreach迴圈寫法
 

	int[] foo = new int[100];
foreach(int i in foo)
    Console.WriteLine(i.ToString());

 

 

2.for迴圈寫法

	int[] foo = new int[100];
for(int index=0;index<foo.Length;index++)
    Console.WriteLine(foo[index].ToString());

 

3.for迴圈寫法 (結束條件提到迴圈外)

	int[] foo = new int[100];
int len = foo.Length;
for(int index=0;index<len;index++)
    Console.WriteLine(foo[index].ToString());

 

據作者所述,第一個迴圈的寫法,在.NET1.1以後的版本,其效率最佳,程式碼也最少。而第三個迴圈寫法是最慢的,因為這樣刻意的把結束條件提出迴圈外,會阻礙JIT編譯器移除迴圈內的範圍檢查,讓JIT編譯器編譯成下面這樣:

	int[] foo = new int[100];
int len = foo.Length;
for(int index=0;index<len;index++){
    if(index<foo.Length)
        Console.WriteLine(foo[index].ToString());
    else
        throw new IndexOutOfRangeException();
}

 

在.NET 1.0以前,使用foreach效率上會較差,因為JIT編譯器會把程式編譯成下面這樣:

	IEnumerator it = foo.GetEnumerator();
while(it.MoveNext())
{
   int i = (int) it.Current;
   Console.WriteLine(i.ToString());
}

 

這樣的程式會產生裝箱與拆箱,因此在效能上會有不良的影響。但在.NET 1.1以後的版本,JIT編譯器會把程式編譯成下面這樣:

	int[] foo = new int[100];
for(int index=0;index<foo.Length;index++)
    Console.WriteLine(foo[index].ToString());

 

 

所以我們可以得知,使用foreach來處理迴圈,編譯器會幫我們自動產生最佳的程式碼,程式也較短較易閱讀。

 

不過經實際實驗,當撰寫了如下測試程式:

	static void Main(string[] args)
        {
            int[] foo = new int[100];
            int len = foo.Length;

            foreach (int i in foo)
                Console.WriteLine(i.ToString());

            for (int index = 0; index < len; index++)
                Console.WriteLine(foo[index].ToString());

            for (int index = 0; index < foo.Length; index++)
                Console.WriteLine(foo[index].ToString());
        }

 

用Reflector反組譯工具來查看,該段程式被編譯後是幾乎不變的。

image

 

這邊就留待個人自己去評估。

 

除效能外,foreach迴圈在使用上也具備較高的相容性。不論巡覽的陣列其上下限是多少,foreach迴圈總是能正確的運行。在多維陣列上,不論陣列維度維多少,使用foreach迴圈都能幫我們巡覽所有陣列元素。就算本來使用的是陣列,後來因需求變更為使用集合類別,使用foreach迴圈,程式都不需做任何的修改。

 

綜合以上論點,在撰寫巡覽迴圈元素的程式時,我們應該優先考慮使用foreach迴圈寫法。因其可獲得較好的效能與較高的相容性,也可提升開發速度與可讀性。