【FastReport教程】在C#中的Foreach
【下載FastReport.Net最新版本】
我們都知道foreach循環(huán)是 - 循環(huán)遍歷集合的所有元素。它在易用性方面的最大優(yōu)勢 - 我們不需要擔心集合中有多少元素。然而,許多人不知道這只是語法“sugar”,這有利于程序員的工作。因此,我們只需知道生成的編譯器將轉(zhuǎn)換的內(nèi)容。foreach循環(huán)的工作方式不同,具體取決于您要排序的集合。
(1)如果必須處理平凡陣列,我們總能知道它的長度。因此,foreach最終將轉(zhuǎn)換為for循環(huán)。例如:
int[] array = new int[]{1, 2, 3, 4, 5, 6}; foreach (int item in array) { Console.WriteLine(item); }
編譯器將循環(huán)轉(zhuǎn)換為此構(gòu)造:
int[] temp; int[] array = new int[]{1, 2, 3, 4, 5, 6}; temp = array; for (int i = 0; i < temp.Length; i++) { int item = temp[i]; Console.WriteLine(item); }
(2)但是,許多集合不支持對元素的索引訪問,例如:Dictionary,Queue,Stack。在這種情況下,將使用迭代器模板。此模板基于接口System.Collections.Generic.IEnumerator 和非通用System.Collections.IEnumerator,它允許您迭代集合中的元素。IEnumerator包含:
- MoveNext()方法 - 將枚舉數(shù)移動到集合的下一個元素;
- Reset()方法 - 重新啟動枚舉,將枚舉數(shù)設(shè)置為起始位置;
- Current屬性 - 返回集合的當前元素。
IEnumirator 繼承自兩個接口 - IEnumirator和IDisposable。它包含Current屬性的重載,按類型提供其實現(xiàn)。既然我們提到了接口IDisposable,那么我們就會說幾句話。它包含釋放資源所需的唯一Dispose()方法。每次循環(huán)終止或退出時,IEnumirator 都會清除資源。我們來看看這個循環(huán):
System.Collections.Generic.Queue<int> queue = new System.Collections.Generic.Queue<int>(); queue.Enqueue(1); queue.Enqueue(2); queue.Enqueue(3); foreach (int item in queue) { Console.WriteLine(item); }
編譯器將其轉(zhuǎn)換為類似的代碼:
System.Collections.Generic.Queue<int> queue = new System.Collections.Generic.Queue<int>(); queue.Enqueue(1); queue.Enqueue(2); queue.Enqueue(3); int num; while (queue.MoveNext()) { num = queue.Current; Console.WriteLine(num); }
在此示例中,MoveNext替換了在循環(huán)期間計算元素的需要。當它沒有收到下一個元素時,它返回fasle并且循環(huán)終止。 但是,盡管如此,這段代碼只是近似于編譯器的真正產(chǎn)生。問題是,如果您有兩個或更多重疊循環(huán)使用相同的集合,則每個MoveNext調(diào)用將影響所有循環(huán)。這個過程不適合任何人。想出了第二個接口IEnumirator。
它包含唯一的方法GetEnumerator(),它返回一個枚舉器。因此,IEnumerable 及其IEnumerable的通用版本允許您呈現(xiàn)枚舉集合類中的元素的邏輯。通常,這是一個嵌套類,可以訪問集合的元素并支持IEnumerator 。擁有每個枚舉器,不同的消費者不會相互干擾,同時執(zhí)行集合的枚舉。 因此,上面的例子應(yīng)該考慮兩點 - 獲得一個枚舉器和釋放資源。以下是編譯器實際轉(zhuǎn)換foreach循環(huán)代碼的方法:
System.Collections.Generic.Queue<int> queue = new System.Collections.Generic.Queue<int>(); System.Collections.Generic.Queue<int>.Enumerator enumirator; IDisposable disposable; enumirator = queue.GetEnumerator(); queue.Enqueue(1); queue.Enqueue(2); queue.Enqueue(3); try { int num; while (enumirator.MoveNext()) { num = enumirator.Current; Console.WriteLine(num); } } finally { disposable = (IDisposable)enumirator; disposable.Dispose(); }
您可能認為對于集合的迭代,您需要實現(xiàn)IEnumerable和IEnumerable 接口。但是,這并不完全正確。要編譯foreach,只需要實現(xiàn)GetEnumerator()方法,該方法將返回另一個具有Current屬性和MoveNext()方法的對象。 這里我們使用duck typing - 一種眾所周知的方法。
也就是說,如果有一個GetEnumerator()方法的對象,它返回一個帶有MoveNext()方法和Current屬性的對象,那么這就是枚舉器。 否則,如果找不到必要的對象,并且找不到必要的方法,則將搜索IEnumerable和IEnumerable 接口。 因此,foreach實際上是一個通用循環(huán),可以同時適用于數(shù)組和集合。我經(jīng)常使用它。但是,foreach有一個缺點 - 它只允許讀取元素,并且不允許更改它們。