C# —— IEnumerator和foreach
在我的最新帖子中,我使用了名為“ EnumerateFiles” 的DirectoryInfo方法。但是,如果我們研究DirectoryInfo的可用的方法,我們將注意到還有一個“ GetFiles”方法,它具有相同的過載和引數個數,但就是這兩種方法之間的差異,以及為什麼我選擇使用“ EnumerateFiles”方法。
那麼,回答這個問題,我們將必須檢視.NET的內部工作中發生了什麼,為此,我們還必須檢視Enumerators 是什麼以及它們是如何工作的。
讓我們從foreach構造開始。
因為foreach聽起來很像for構造,所以有些人可能認為
我們知道,for迴圈定義如下:
for(int index; index < Number; index++) { ...code to execute... }
而foreach迴圈定義是這樣的:
foreach(var item in COLLECTION) { ... code to execute ... }
但.NET框架如何在沒有條件存在的情況下知道何時停止?嗯,簡單的答案是,它不知道何時停止。我的意思是.NET Framework使用.NET中的Iterators
基本上,在.NET中找到的所有集合都與Enumerators 一起使用,這對於foreach迴圈是必需的。
所以,讓我們更深入一些,Enumerator是一個物件,它具有一個Current屬性和兩個名為Reset和MoveNext的方法,所以如果我們有一個集合,比如說一個專案的列表,我們在foreach迴圈中使用它,那麼foreach將呼叫MoveNext,它將Current屬性設定為列表中的下一個專案,如果下一個物件被發現,則返回true或false,但如果在該列表中找不到更多物件,則該Current物件將設定為null。
使用這個工作流程,我們還可以使用
因此,如果我們要實現一個Enumerator,它只給我們偶數的數字,我們將實現這樣的MoveNext方法:
public bool MoveNext() { Current = Current + 2; return true; }
現在,如果你注意到,前面我們只返回true,這意味著,如果這個Enumerator是與foreach迴圈被一起使用,那麼它將永遠執行,除非我們阻止它,或者如果我們設定了overflow檢查,直到它達到int的最大大小和然後丟擲異常。
使用這個工作流程的另一個結果(你們中的一些人可能會遇到它)是,如果我們將foreach迴圈與集合一起使用,那麼我們就無法修改該迴圈內的集合,如果我們嘗試修改,那麼將丟擲異常。
但是Enumerator除了允許我們使用foreach構造之外,還有另一個好處,那就是我們在執行MoveNext方法時一次使用一個物件。
回到我們的“ GetFiles” vs “EnumerateFiles” 的例子,讓我們用它作為一個包含1000個檔案的資料夾的例子。
當我們呼叫“ GetFiles”方法時,我們將收到該目錄中所有1000個檔案的陣列,但是我們還必須等到方法遍歷每個檔案,將其轉換為 FileInfo並將其新增到其內部陣列,然後再返回給我們。之後,我們可以迴圈瀏覽這些檔案,並利用它們進行工作。
另一方面,當我們呼叫“ EnumerateFiles”方法時,該方法將查詢檔案,獲取它遇到的第一個檔案,將其返回給我們,我們執行我們想要針對該檔案的工作,然後我們將進入下一個檔案。
現在想象那個目錄或資料夾,其中有成千上萬的檔案,其中一些甚至巢狀在其他資料夾中的更深處,然後使用“ GetFiles”方法是非常低效的,更糟糕的是,每次我們呼叫方法時,我們得到一個整個集合,這意味著如果我們想要並行處理多個檔案,我們必須管理哪個迴圈與哪個檔案一起工作,這樣我們就不會重疊,在這種情況下foreach迴圈利用這種Enumerator,將使我們的工作更容易,因為我們一次只能處理一件檔案,每次我們申請新檔案時,我們都會繼續前進。
原文地址:https://www.codeproject.com/Articles/1266989/IEnumerator-and-foreach