共用方式為


逐步解說:在 Visual Basic 中實作 IEnumerable(Of T)

介面 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

建立可列舉類別

建立可列舉類別專案

  1. 在 Visual Basic 的 [ 檔案 ] 功能表上,指向 [ 新增 ],然後按兩下 [ 專案]。

  2. 在 [ 新增專案] 對話框中的 [ 項目類型 ] 窗格中,確定已選取 Windows 。 在 [範本] 窗格中選取 [類別庫]。 在 [ 名稱] 方塊中,輸入 StreamReaderEnumerable,然後按兩下 [ 確定]。 顯示新的專案。

  3. 方案管理員 中,以滑鼠右鍵點擊 Class1.vb 檔案,然後選擇 重新命名。 將檔案重新命名為 StreamReaderEnumerable.vb ,然後按 ENTER 鍵。 重新命名檔案也會將 類別重新命名為 StreamReaderEnumerable。 這個類別會實作 IEnumerable(Of String) 介面。

  4. 以滑鼠右鍵按兩下 StreamReaderEnumerable 專案,指向 [ 新增],然後按兩下 [ 新增專案]。 選取 [類別 ] 範本。 在 [ 名稱] 方塊中,輸入 StreamReaderEnumerator.vb 並按兩下 [確定]。

此專案中的第一個類別是可列舉的類別,而且會實作 IEnumerable(Of String) 介面。 這個泛型介面會實作 IEnumerable 介面,並保證此類別的取用者可以存取類型為 String的值。

新增程式代碼以實作 IEnumerable

  1. 開啟StreamReaderEnumerable.vb檔案。

  2. 在 之後 Public Class StreamReaderEnumerable的行上,輸入下列命令,然後按 ENTER 鍵。

    Implements IEnumerable(Of String)
    

    Visual Basic 會自動將 介面所需的 IEnumerable(Of String) 成員填入 類別。

  3. 這個可列舉類別會逐行從文本文件讀取。 將下列程式代碼新增至 類別,以公開以檔案路徑作為輸入參數的公用建構函式。

    Private _filePath As String
    
    Public Sub New(ByVal filePath As String)
        _filePath = filePath
    End Sub
    
  4. 您對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

  1. 開啟StreamReaderEnumerator.vb檔案。

  2. 在 之後 Public Class StreamReaderEnumerator的行上,輸入下列命令,然後按 ENTER 鍵。

    Implements IEnumerator(Of String)
    

    Visual Basic 會自動將 介面所需的 IEnumerator(Of String) 成員填入 類別。

  3. 列舉值類別會開啟文本檔,並執行檔案 I/O 以從檔案讀取行。 將下列程式代碼新增至 類別,以公開以檔案路徑作為輸入參數的公用建構函式,並開啟文本檔以供讀取。

    Private _sr As IO.StreamReader
    
    Public Sub New(ByVal filePath As String)
        _sr = New IO.StreamReader(filePath)
    End Sub
    
  4. CurrentIEnumerator(Of String) 介面的屬性會將文字檔案中的目前項目傳回為 IEnumerator。 介面CurrentIEnumerator屬性實作可以是 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
    
  5. 介面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
    
  6. Reset 方法所屬的 IEnumerator 介面會指示反覆運算器指向文字檔案的開頭,並清除當前項目值。 將下列程式碼新增至 Reset 方法。

    Public Sub Reset() _
        Implements System.Collections.IEnumerator.Reset
    
        _sr.DiscardBufferedData()
        _sr.BaseStream.Seek(0, IO.SeekOrigin.Begin)
        _current = Nothing
    End Sub
    
  7. 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()

另請參閱