1. 程式人生 > >C# —— IEnumerator和foreach

C# —— IEnumerator和foreach

在我的最新帖子中,我使用了名為“ EnumerateFiles” DirectoryInfo方法。但是,如果我們研究DirectoryInfo可用的方法,我們將注意到還有一個“ GetFiles”方法,它具有相同的過載和引數個數,但就是這兩種方法之間的差異,以及為什麼我選擇使用“ EnumerateFiles方法。

那麼,回答這個問題,我們將必須檢視.NET的內部工作中發生了什麼,為此,我們還必須檢視Enumerators 是什麼以及它們是如何工作的。

讓我們從foreach構造開始。

因為foreach聽起來很像for構造,所以有些人可能認為

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

概念或更常見的作為Enumerators

基本上,在.NET中找到的所有集合都與Enumerators 一起使用,這對於foreach迴圈是必需的。

所以,讓我們更深入一些,Enumerator是一個物件,它具有一個Current屬性和兩個名為ResetMoveNext的方法,所以如果我們有一個集合,比如說一個專案的列表,我們在foreach迴圈中使用它,那麼foreach將呼叫MoveNext,它將Current屬性設定為列表中的下一個專案,如果下一個物件被發現,則返回truefalse,但如果在該列表中找不到更多物件,則該Current物件將設定為null

使用這個工作流程,我們還可以使用

.NET中的另一個迴圈,並手動呼叫MoveNext方法和Current屬性,實際上有一些演算法仍在使用手動呼叫。

因此,如果我們要實現一個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