1. 程式人生 > >C# 迴圈語句foreach用法

C# 迴圈語句foreach用法

foreach迴圈用於列舉出集合中所有的元素,foreach語句中的表示式由關鍵字in隔開的兩個項組成。in右邊的項是集合名,in左邊的項是變數名,用來存放該集合中的每個元素。

該迴圈的執行過程如下:每一次迴圈時,從集合中取出一個新的元素值。放到只讀變數中去,如果括號中的整個表示式返回值為true,foreach塊中的語句就能夠執行。一旦集合中的元素都已經被訪問到,整個表示式的值為false,控制流程就轉入到foreach塊後面
的執行語句。

foreach語句經常與陣列一起使用,下面例項將通過foreach語句讀取陣列的值並進行顯示。

陣列的屬性:Array.Length陣列的容量

利用這個屬性,我們可以取得陣列物件允許儲存的容量值,也就是陣列的長度、元素個數,這個比較好理解,陣列還有其他的屬性,比如陣列的維數等,屬性的用法比較簡單,學會一種,其他的格式基本一致,這裡我們就不舉例了。

當陣列的維數、容量較多時,C#提供了foreach語句,專門用來讀取集合/陣列中的所有元素,我們把這種功能叫做遍歷。語法書寫如下:

遍歷陣列:foreach(type objName in collection/Array)

這段語句會逐一檢查陣列中的所儲存的變數值,並且一一將其取出,其中的type是你所要讀取的陣列物件將要儲存在objName變數的資料型別,而objName是定義了一個type型別的變數名,代表每一次從集合和陣列(collection/Array)中取得的元素,collection/Array則是所要存取的陣列物件。用這種方法只需寫一個foreach就可以遍歷出除交錯陣列以外的所有維數的陣列。

注: objName的資料型別type必須與collection/Array物件的型別相同或比它大。

下面我們舉一個用foreach和for遍歷規則陣列的例子,其中涉及到了一個數組得到維數的方法,比較foreach在一次性遍歷規則陣列上的優勢。

           int[,,] a = new int[2, 2, 2] { {{ 1, 2 }, { 3,4}},{{ 5, 6 }, { 7,8}} };//定義一個2行2列2縱深的3維陣列a

            for (int i = 0; i < a.GetLength (0) ;i++ )   //用Array.GetLength(n)得到陣列[0,1,,,n]上的維數的元素數,0代表行,1列,n代表此陣列是n+1維

            {

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

                {

                    for (int z = 0; z < a.GetLength(2);z++ )//2代表得到縱深上的元素數,如果陣列有n維就得寫n個for迴圈

                    {

                        Console.WriteLine(a[i,j,z]);

                    }

                }

            }

用foreach迴圈一次性遍歷a陣列

          int[,,] a = new int[2, 2, 2] { {{ 1, 2 }, { 3,4}},{{ 5, 6 }, { 7,8}} };//定義一個2行2列2縱深的3維陣列a
                      foreach(int i in a)
                      {
                          Console .WriteLine (i);
                      }

這兩種程式碼執行的結果是一樣的都是 每行一個元素,共8行,元素分別是1 2 3 4 5 6 7 8

下面我們再做個例子,是一個利用for和foreach迴圈做的存取陣列元素的例子,首先提示使用者輸入學生的個數,然後把學生個數作為儲存學生姓名的陣列names的元素個數,採用for迴圈按照陣列的索引i從0位開始迴圈輸出“輸入學生姓名”的提示,並把使用者輸入的學生姓名按照其在陣列的索引方式names[i]儲存在names陣列中,for迴圈次數的最大值(即索引的最大值)通過陣列屬性.Length得到,我們說過容量與索引之間的關係是index=Array.Length-1,本題即i的最大值<names.Length,儲存後,提示“輸出學生姓名”,再用foreach迴圈一次性遍歷names陣列中儲存的每個元素(學生的姓名),一個一個的把它賦值給name元素,然後輸出到控制檯上。

必須注意的是,藉助foreach,只能一一取得陣列中的元素,並不能利用這種語句改變陣列所儲存的元素。

迴圈語句是程式設計的基本語句,在C#中除了沿用C語言的迴圈語句外,還提供了foreach語句來實現迴圈。那麼我要說的就是,在迴圈操作中儘量使用foreach語句來實現。 為了來更好地說明為什麼要提倡使用foreach,用如下三種不同方式來編寫迴圈語句。         int[] nArray = new int[100];         // Use "foreach" to loop array         foreachint i in nArray )             Debug.WriteLine( i.ToString() );         // Use "for" to loop array         forint i = 0; i < nArray.Length; i++ )             Debug.WriteLine( nArray[i].ToString() );         // Another way using "for" to loop array         int nLength = nArray.Length;         forint i = 0; i < nLength; i++ )             Debug.WriteLine( nArray[i].ToString() ); 很明顯,foreach語句很簡潔,但是它的優點不僅僅在於此,它的效率也是最高的。可能很多人認為最後一種的效率會更高,因為表面上看著不用每次訪問引用型別的屬性。可是它卻是三者當中,效率最低的。因為C#是強型別檢查,那麼對於陣列訪問的時候,要對索引的有效值進行判斷,那麼對於最後一種程式碼實際產生的效果如同下面的程式碼一樣。         // Another way using "for" to loop array         int nLength = nArray.Length;         forint 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         forint i = 0; i < nVisited.GetLength(0); i++ )             forint j = 0; j < nVisited.GetLength( 1 ); j++ )                 Debug.WriteLine( nVisited[i,j].ToString() );         // Use "foreach" to loop two-dimension array         foreachint 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         foreachint i in arrInt )             Debug.WriteLine( i.ToString() );         // Use "for" to loop an arraylist         forint 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         foreachint i in arrInt )         {             i++;//Can't be compiled             Debug.WriteLine( i.ToString() );         }         // Use "foreach" to loop an arraylist         foreachint i in arrInt )         {             arrInt.Remove( i );//It will generate error in run-time             Debug.WriteLine( i.ToString() );         } 那麼對於如上兩個操作,可以用for來實現,此外這裡多說一句,就是對於一個記錄集的多條資料刪除問題,也是經常出現問題的地方(論壇上經常問類似的問題),由於在一些記錄集中進行刪除的時候,在刪除操作之後相應的索引也發生了變化,這時候的刪除要反過來進行刪除,大致形式如下。         // Use "for" to loop an arraylist         forint 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,因為它會使你的程式碼清晰簡潔,又不失高效。