Condividi tramite


Procedura dettagliata: Implementazione di IEnumerable(Of T) in Visual Basic

L'interfaccia IEnumerable<T> viene implementata dalle classi che possono restituire una sequenza di valori un elemento alla volta. Il vantaggio di restituire dati un elemento alla volta è che non è necessario caricare il set completo di dati in memoria per usarlo. È sufficiente usare memoria sufficiente per caricare un singolo elemento dai dati. Le classi che implementano l'interfaccia IEnumerable(T) possono essere utilizzate con cicli For Each o con query LINQ.

Si consideri, ad esempio, un'applicazione che deve leggere un file di testo di grandi dimensioni e restituire ogni riga dal file che corrisponde a criteri di ricerca specifici. L'applicazione usa una query LINQ per restituire righe dal file che soddisfano i criteri specificati. Per eseguire query sul contenuto del file usando una query LINQ, l'applicazione potrebbe caricare il contenuto del file in una matrice o in una raccolta. Tuttavia, il caricamento dell'intero file in una matrice o in una raccolta richiederebbe molto più memoria di quanto richiesto. La query LINQ potrebbe invece eseguire query sul contenuto del file usando una classe enumerabile, restituendo solo valori che corrispondono ai criteri di ricerca. Le query che restituiscono solo alcuni valori corrispondenti consumano molto meno memoria.

È possibile creare una classe che implementa l'interfaccia IEnumerable<T> per esporre i dati di origine come dati enumerabili. La classe che implementa l'interfaccia IEnumerable(T) richiederà un'altra classe che implementa l'interfaccia IEnumerator<T> per scorrere i dati di origine. Queste due classi consentono di restituire elementi di dati in sequenza come tipo specifico.

In questa procedura dettagliata si creerà una classe che implementa l'interfaccia IEnumerable(Of String) e una classe che implementa l'interfaccia IEnumerator(Of String) per leggere un file di testo una riga alla volta.

Annotazioni

Il computer potrebbe visualizzare nomi o percorsi diversi per alcuni degli elementi dell'interfaccia utente di Visual Studio nelle istruzioni seguenti. L'edizione di Visual Studio disponibile e le impostazioni usate determinano questi elementi. Per altre informazioni, vedere Personalizzazione dell'IDE.

Creazione della classe Enumerable

Creare il progetto di classe enumerabile

  1. In Visual Basic scegliere Nuovo dal menu File e quindi fare clic su Progetto.

  2. Nel riquadro Tipi di progetto della finestra di dialogo Nuovo progetto verificare che Sia selezionato Windows. Selezionare Libreria di classi nel riquadro Modelli . Nella casella Nome digitare StreamReaderEnumerablee quindi fare clic su OK. Viene visualizzato il nuovo progetto.

  3. In Esplora soluzioni fare clic con il pulsante destro del mouse sul file Class1.vb e scegliere Rinomina. Rinominare il file StreamReaderEnumerable.vb in e premere INVIO. La ridenominazione del file rinomina anche la classe in StreamReaderEnumerable. Questa classe implementerà l'interfaccia IEnumerable(Of String) .

  4. Fare clic con il pulsante destro del mouse sul progetto StreamReaderEnumerable, scegliere Aggiungi e quindi fare clic su Nuovo elemento. Selezionare il modello Classe . Nella casella Nome digitare StreamReaderEnumerator.vb e fare clic su OK.

La prima classe in questo progetto è la classe enumerabile e implementerà l'interfaccia IEnumerable(Of String) . Questa interfaccia generica implementa l'interfaccia IEnumerable e garantisce che i consumer di questa classe possano accedere ai valori tipizzati come String.

Aggiungere il codice per implementare IEnumerable

  1. Aprire il file StreamReaderEnumerable.vb.

  2. Nella riga dopo Public Class StreamReaderEnumerabledigitare quanto segue e premere INVIO.

    Implements IEnumerable(Of String)
    

    Visual Basic popola automaticamente la classe con i membri richiesti dall'interfaccia IEnumerable(Of String) .

  3. Questa classe enumerabile leggerà le righe da un file di testo una riga alla volta. Aggiungere il codice seguente alla classe per esporre un costruttore pubblico che accetta un percorso di file come parametro di input.

    Private _filePath As String
    
    Public Sub New(ByVal filePath As String)
        _filePath = filePath
    End Sub
    
  4. L'implementazione del GetEnumerator metodo dell'interfaccia IEnumerable(Of String) restituirà una nuova istanza della StreamReaderEnumerator classe . L'implementazione del GetEnumerator metodo dell'interfaccia IEnumerable può essere eseguita Privateperché è necessario esporre solo i membri dell'interfaccia IEnumerable(Of String) . Sostituire il codice generato da Visual Basic per i GetEnumerator metodi con il codice seguente.

    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
    

Aggiungere il codice per implementare IEnumerator

  1. Aprire il file StreamReaderEnumerator.vb.

  2. Nella riga dopo Public Class StreamReaderEnumeratordigitare quanto segue e premere INVIO.

    Implements IEnumerator(Of String)
    

    Visual Basic popola automaticamente la classe con i membri richiesti dall'interfaccia IEnumerator(Of String) .

  3. La classe enumeratore apre il file di testo ed esegue l'I/O del file per leggere le righe dal file. Aggiungere il codice seguente alla classe per esporre un costruttore pubblico che accetta un percorso di file come parametro di input e aprire il file di testo per la lettura.

    Private _sr As IO.StreamReader
    
    Public Sub New(ByVal filePath As String)
        _sr = New IO.StreamReader(filePath)
    End Sub
    
  4. Le proprietà Current per entrambe le interfacce IEnumerator(Of String) e IEnumerator restituiscono l'elemento corrente dal file di testo come String. L'implementazione della Current proprietà dell'interfaccia IEnumerator può essere eseguita Privateperché è necessario esporre solo i membri dell'interfaccia IEnumerator(Of String) . Sostituire il codice generato da Visual Basic per le Current proprietà con il codice seguente.

    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. Il MoveNext metodo dell'interfaccia IEnumerator passa all'elemento successivo nel file di testo e aggiorna il valore restituito dalla Current proprietà . Se non sono presenti altri elementi da leggere, il MoveNext metodo restituisce False. In caso contrario, il MoveNext metodo restituisce True. Aggiungere il codice seguente al metodo 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. Il metodo Reset dell'interfaccia IEnumerator indirizza l'iteratore a puntare all'inizio del file di testo e cancella il valore dell'elemento corrente. Aggiungere il codice seguente al metodo Reset.

    Public Sub Reset() _
        Implements System.Collections.IEnumerator.Reset
    
        _sr.DiscardBufferedData()
        _sr.BaseStream.Seek(0, IO.SeekOrigin.Begin)
        _current = Nothing
    End Sub
    
  7. Il Dispose metodo dell'interfaccia IEnumerator garantisce che tutte le risorse non gestite vengano rilasciate prima che l'iteratore venga eliminato definitivamente. L'handle di file utilizzato dall'oggetto StreamReader è una risorsa non gestita e deve essere chiuso prima che l'istanza dell'iteratore venga eliminata definitivamente. Sostituire il codice generato da Visual Basic per il Dispose metodo con il codice seguente.

    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
    

Uso dell'iteratore di esempio

È possibile usare una classe enumerabile nel codice insieme alle strutture di controllo che richiedono un oggetto che implementa IEnumerable, ad esempio un For Next ciclo o una query LINQ. Nell'esempio seguente viene illustrato il StreamReaderEnumerable in una query LINQ.

Dim adminRequests =
    From line In New StreamReaderEnumerable("..\..\log.txt")
    Where line.Contains("admin.aspx 401")

Dim results = adminRequests.ToList()

Vedere anche