《Effective C#》Item 11:提倡使用foreach語句來進行循環操作

循環語句是編程的基本語句,在C#中除了沿用C語言的循環語句外,還提供了foreach語句來實現循環。那麼我要說的就是,在循環操作中儘量使用foreach語句來實現。

 

爲了來更好地說明爲什麼要提倡使用foreach,用如下三種不同方式來編寫循環語句。

        int[] nArray = new int[100];

 

        // Use "foreach" to loop array

        foreach( int i in nArray )

            Debug.WriteLine( i.ToString() );

 

        // Use "for" to loop array

        for( int i = 0; i < nArray.Length; i++ )

            Debug.WriteLine( nArray[i].ToString() );

 

        // Another way using "for" to loop array

        int nLength = nArray.Length;

        for( int i = 0; i < nLength; i++ )

            Debug.WriteLine( nArray[i].ToString() );

 

很明顯,foreach語句很簡潔,但是它的優點不僅僅在於此,它的效率也是最高的。可能很多人認爲最後一種的效率會更高,因爲表面上看着不用每次訪問引用類型的屬性。可是它卻是三者當中,效率最低的。因爲C#是強類型檢查,那麼對於數組訪問的時候,要對索引的有效值進行判斷,那麼對於最後一種代碼實際產生的效果如同下面的代碼一樣。

        // Another way using "for" to loop array

        int nLength = nArray.Length;

        for( int i = 0; i < nLength; i++ )

        {

            if( i < nArray.Length )

                Debug.WriteLine( nArray[i].ToString() );

            else

                throw new IndexOutOfRangeException();

        }

(書中這裏有些出入,經過網友sozdream的提示,在1.1環境下發現最後一種方法是最快的,前兩者的速度基本相等;通過Dissambly查看最後一種循環方法所產生的代碼,並沒有產生類似於文章所說的那種索引檢查。不過還是不建議使用最後一種,因爲此方法對索引的判斷有些脫節,尤其是當循環中數組尺寸發生變化的時候,索引有效檢查無法及時進行)

 

foreach語句除了簡潔和高效外,還有很多優點,接下來一一列舉。

 

第一個就是不用考慮數組起始索引是幾,很多人可能從其他語言轉到C#的,那麼原先語言的起始索引可能不是1,例如VB或者Delphi語言,那麼在C#中使用數組的時候就難免疑問到底使用0開始還是用1開始呢,那麼使用foreach就可以避免這類問題。

 

第二個好處就是對於多維數組操作用foreach就非常簡便了,例如:

        int[,] nVisited = new int[8,8];

        // Use "for" to loop two-dimension array

        for( int i = 0; i < nVisited.GetLength(0); i++ )

            for( int j = 0; j < nVisited.GetLength( 1 ); j++ )

                Debug.WriteLine( nVisited[i,j].ToString() );

 

        // Use "foreach" to loop two-dimension array

        foreach( int i in nVisited )

            Debug.WriteLine( i.ToString() );

 

對於三維或更多維,foreach語句不用發生任何變化,而對於for語句來說就要進行修改了,這裏就不多說了。

 

第三個要說的就是foreach完成類型轉換操作,這種體現可能通過如上的例子看不出任何效果,但是對於ArrayList之類的數據集來說,這種操作就顯得比較突出,例如:

        // Init an arraylist object

        int[] nArray = new int[100];

        ArrayList arrInt = new ArrayList();

        arrInt.AddRange( nArray );

 

        // Use "foreach" to loop an arraylist

        foreach( int i in arrInt )

            Debug.WriteLine( i.ToString() );

 

        // Use "for" to loop an arraylist

        for( int i = 0; i < arrInt.Count; i++ )

        {

            int n = ( int ) arrInt[i];

            Debug.WriteLine( n.ToString() );

        }

 

最後要說的是使用foreach並沒有增加資源使用,這句話聽得有些難懂,由於對於繼承了IEnumerable接口的類型數據,才能使用foreach語句,那麼對於使用foreach會訪問IEnumerable接口中GetEnumerator方法來進行枚舉,那麼對於如上的foreach語句,對應的語句其實如下:

        IEnumerator it = arrInt.GetEnumerator() as IEnumerator;

        using( IDisposable disp = it as IDisposable )

        {

            while( it.MoveNext() )

            {

                int elem = ( int )it.Current;

                Debug.WriteLine( elem.ToString() );

            }

        }

 

也就是說在出了foreach之後對於IEnumerator的對象也進行Dispose處理。

 

對於foreach說了這麼多好處,那麼在使用它是否可以無懈可擊呢。其實不是這樣的,foreach語句中有兩個限制,第一不能修改枚舉成員,其次不要對集合進行刪除操作。也就是如下兩種方式都是錯誤的。

        // Use "foreach" to loop an arraylist

        foreach( int i in arrInt )

        {

            i++;//Can't be compiled

            Debug.WriteLine( i.ToString() );

        }

 

        // Use "foreach" to loop an arraylist

        foreach( int i in arrInt )

        {

            arrInt.Remove( i );//It will generate error in run-time

            Debug.WriteLine( i.ToString() );

        }

 

那麼對於如上兩個操作,可以用for來實現,此外這裏多說一句,就是對於一個記錄集的多條數據刪除問題,也是經常出現問題的地方(論壇上經常問類似的問題),由於在一些記錄集中進行刪除的時候,在刪除操作之後相應的索引也發生了變化,這時候的刪除要反過來進行刪除,大致形式如下。

        // Use "for" to loop an arraylist

        for( int i = arrInt.Count - 1; i >=0; i-- )

        {

            int n = ( int ) arrInt[i];

            if( n == 5 )

                arrInt.RemoveAt( i ); // Remove data here

            Debug.WriteLine( n.ToString() );

        }

 

除了這兩個地方外,foreach可以基本適用於任何循環,因此對於循環的編寫要儘量使用foreach,因爲它會使你的代碼清晰簡潔,又不失高效。

發佈了87 篇原創文章 · 獲贊 9 · 訪問量 100萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章