介面 IEnumerable<T> 是由類別所實作的,這些類別可以一次傳回一個值的序列。 一次傳回數據一個項目的優點是,您不需要將完整的數據集載入記憶體中,即可進行操作。 您只需要使用足夠的記憶體從資料載入單一項目。 實作介面的 IEnumerable(T)
類別可以搭配 For Each
迴圈或LINQ查詢使用。
例如,假設應用程式必須讀取大型文本檔,並從符合特定搜尋準則的檔案傳回每一行。 應用程式會使用 LINQ 查詢,從符合指定準則的檔案傳回行。 若要使用 LINQ 查詢來查詢檔案的內容,應用程式可以將檔案的內容載入數位或集合中。 不過,將整個檔案載入數位或集合會耗用比所需的記憶體還多得多。 LINQ 查詢可以改為使用可列舉類別來查詢檔案內容,只傳回符合搜尋準則的值。 只傳回少數相符值的查詢會耗用較少的記憶體。
您可以建立實作 介面的 IEnumerable<T> 類別,將源數據公開為可列舉的數據。 實作 IEnumerable(T)
介面的類別需要另一個實作 IEnumerator<T> 介面的類別來迭代處理源數據。 這兩個類別可讓您以順序方式傳回資料項目作為指定的類型。
在本逐步解說中,您將建立一個類別以實作 IEnumerable(Of String)
介面,以及一個類別以實作 IEnumerator(Of String)
介面,以逐行讀取文本檔。
備註
您的電腦可能會在下列指示中顯示某些 Visual Studio 使用者介面元素的不同名稱或位置。 您擁有的 Visual Studio 版本,以及您所使用的設定會決定這些元素。 如需詳細資訊,請參閱 個人化 IDE。
建立可列舉類別
建立可列舉類別專案
在 Visual Basic 的 [ 檔案 ] 功能表上,指向 [ 新增 ],然後按兩下 [ 專案]。
在 [ 新增專案] 對話框中的 [ 項目類型 ] 窗格中,確定已選取 Windows 。 在 [範本] 窗格中選取 [類別庫]。 在 [ 名稱] 方塊中,輸入
StreamReaderEnumerable
,然後按兩下 [ 確定]。 顯示新的專案。在 方案管理員 中,以滑鼠右鍵點擊 Class1.vb 檔案,然後選擇 重新命名。 將檔案重新命名為
StreamReaderEnumerable.vb
,然後按 ENTER 鍵。 重新命名檔案也會將 類別重新命名為StreamReaderEnumerable
。 這個類別會實作IEnumerable(Of String)
介面。以滑鼠右鍵按兩下 StreamReaderEnumerable 專案,指向 [ 新增],然後按兩下 [ 新增專案]。 選取 [類別 ] 範本。 在 [ 名稱] 方塊中,輸入
StreamReaderEnumerator.vb
並按兩下 [確定]。
此專案中的第一個類別是可列舉的類別,而且會實作 IEnumerable(Of String)
介面。 這個泛型介面會實作 IEnumerable 介面,並保證此類別的取用者可以存取類型為 String
的值。
新增程式代碼以實作 IEnumerable
開啟StreamReaderEnumerable.vb檔案。
在 之後
Public Class StreamReaderEnumerable
的行上,輸入下列命令,然後按 ENTER 鍵。Implements IEnumerable(Of String)
Visual Basic 會自動將 介面所需的
IEnumerable(Of String)
成員填入 類別。這個可列舉類別會逐行從文本文件讀取。 將下列程式代碼新增至 類別,以公開以檔案路徑作為輸入參數的公用建構函式。
Private _filePath As String Public Sub New(ByVal filePath As String) _filePath = filePath End Sub
您對GetEnumerator介面的
IEnumerable(Of String)
方法的實作會傳回StreamReaderEnumerator
類別的一個新實例。 介面GetEnumerator
的方法IEnumerable
可以實現為Private
,因為您只需公開介面IEnumerable(Of String)
的成員。 以下列程式代碼取代 Visual Basic 為GetEnumerator
方法產生的程式代碼。Public Function GetEnumerator() As IEnumerator(Of String) _ Implements IEnumerable(Of String).GetEnumerator Return New StreamReaderEnumerator(_filePath) End Function Private Function GetEnumerator1() As IEnumerator _ Implements IEnumerable.GetEnumerator Return Me.GetEnumerator() End Function
新增程式代碼以實作 IEnumerator
開啟StreamReaderEnumerator.vb檔案。
在 之後
Public Class StreamReaderEnumerator
的行上,輸入下列命令,然後按 ENTER 鍵。Implements IEnumerator(Of String)
Visual Basic 會自動將 介面所需的
IEnumerator(Of String)
成員填入 類別。列舉值類別會開啟文本檔,並執行檔案 I/O 以從檔案讀取行。 將下列程式代碼新增至 類別,以公開以檔案路徑作為輸入參數的公用建構函式,並開啟文本檔以供讀取。
Private _sr As IO.StreamReader Public Sub New(ByVal filePath As String) _sr = New IO.StreamReader(filePath) End Sub
Current
和IEnumerator(Of String)
介面的屬性會將文字檔案中的目前項目傳回為IEnumerator
。 介面Current
的IEnumerator
屬性實作可以是Private
,因為您只需要公開IEnumerator(Of String)
介面的成員。 以下列程式代碼取代 Visual Basic 為Current
屬性產生的程式代碼。Private _current As String Public ReadOnly Property Current() As String _ Implements IEnumerator(Of String).Current Get If _sr Is Nothing OrElse _current Is Nothing Then Throw New InvalidOperationException() End If Return _current End Get End Property Private ReadOnly Property Current1() As Object _ Implements IEnumerator.Current Get Return Me.Current End Get End Property
介面
MoveNext
的方法IEnumerator
會導航至文本檔中的下一個專案,並更新Current
屬性傳回的值。 如果沒有其他項目可讀取,則MoveNext
方法會False
傳回 ,否則MoveNext
方法會傳True
回 。 將下列程式碼新增至MoveNext
方法。Public Function MoveNext() As Boolean _ Implements System.Collections.IEnumerator.MoveNext _current = _sr.ReadLine() If _current Is Nothing Then Return False Return True End Function
Reset
方法所屬的IEnumerator
介面會指示反覆運算器指向文字檔案的開頭,並清除當前項目值。 將下列程式碼新增至Reset
方法。Public Sub Reset() _ Implements System.Collections.IEnumerator.Reset _sr.DiscardBufferedData() _sr.BaseStream.Seek(0, IO.SeekOrigin.Begin) _current = Nothing End Sub
Dispose
介面中的IEnumerator
方法保證在迭代器被銷毀之前釋放所有非受控資源。 物件所使用的StreamReader
文件句柄是非受控資源,必須在反覆運算器實例被銷毀之前關閉。 以下列程式代碼取代 Visual Basic 為Dispose
方法產生的程式代碼。Private disposedValue As Boolean = False Protected Overridable Sub Dispose(ByVal disposing As Boolean) If Not Me.disposedValue Then If disposing Then ' Dispose of managed resources. End If _current = Nothing _sr.Close() _sr.Dispose() End If Me.disposedValue = True End Sub Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub Protected Overrides Sub Finalize() Dispose(False) End Sub
使用樣本迭代器
您可以在程式碼中使用可列舉類別,與需要實作 IEnumerable
的物件的控制結構一起使用,例如 For Next
迴圈或 LINQ 查詢。 下列範例顯示 LINQ 查詢中的 StreamReaderEnumerable
。
Dim adminRequests =
From line In New StreamReaderEnumerable("..\..\log.txt")
Where line.Contains("admin.aspx 401")
Dim results = adminRequests.ToList()
另請參閱
- Visual Basic LINQ 簡介
- 控制流程
- 循環結構
- For Each...Next 語句