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. Occorre solo usare memoria sufficiente per caricare un singolo elemento dai dati. Le classi che implementano l'interfaccia IEnumerable(T)
possono essere usate con cicli For Each
o 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. Il caricamento dell'intero file in una matrice o in una raccolta utilizzerebbe tuttavia 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 una quantità decisamente inferiore di 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 eseguire l'iterazione dei dati di origine. Queste due classi consentono di restituire elementi di dati in sequenza come tipo specifico.
In questa procedura dettagliata verrà creata 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.
Nota
I nomi o i percorsi visualizzati per alcuni elementi dell'interfaccia utente di Visual Studio nelle istruzioni seguenti potrebbero essere diversi nel computer in uso. La versione di Visual Studio in uso e le impostazioni configurate determinano questi elementi. Per altre informazioni, vedere Personalizzazione dell'IDE.
Creazione della classe Enumerable
Creare il progetto di classe enumerabile
In Visual Basic scegliere Nuovo dal menu File e quindi fare clic su Progetto.
Nel riquadro Tipi di progetto della finestra di dialogo Nuovo progetto verificare che sia selezionata l'opzione Windows. Selezionare Libreria di classi nel riquadro Modelli. Nella casella Nome digitare
StreamReaderEnumerable
e quindi fare clic su OK. Viene visualizzato il nuovo progetto.In Esplora soluzioni fare clic con il pulsante destro del mouse sul file Class1.vb e fare clic su Rinomina. Rinominare il file
StreamReaderEnumerable.vb
e premere INVIO. Modificando il nome del file, anche la classe verrà rinominataStreamReaderEnumerable
. Questa classe implementerà l'interfacciaIEnumerable(Of String)
.Fare clic con il pulsante destro del mouse sul progetto StreamReaderEnumerable, scegliere Aggiungi e quindi fare clic su Nuovo elemento. Selezionare il modello Classe. Digitare
StreamReaderEnumerator.vb
nella casella Nome e quindi 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
Aprire il file StreamReaderEnumerable.vb.
Nella riga dopo
Public Class StreamReaderEnumerable
digitare quanto segue e premere INVIO.Implements IEnumerable(Of String)
Visual Basic popola automaticamente la classe con i membri richiesti dall'interfaccia
IEnumerable(Of String)
.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
L'implementazione del metodo GetEnumerator dell'interfaccia
IEnumerable(Of String)
restituirà una nuova istanza della classeStreamReaderEnumerator
. L'implementazione del metodoGetEnumerator
dell'interfacciaIEnumerable
può essere resaPrivate
, perché è necessario esporre solo i membri dell'interfacciaIEnumerable(Of String)
. Sostituire il codice generato da Visual Basic per i metodiGetEnumerator
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
Aprire il file StreamReaderEnumerator.vb.
Nella riga dopo
Public Class StreamReaderEnumerator
digitare quanto segue e premere INVIO.Implements IEnumerator(Of String)
Visual Basic popola automaticamente la classe con i membri richiesti dall'interfaccia
IEnumerator(Of String)
.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
Le proprietà
Current
per le interfacceIEnumerator(Of String)
eIEnumerator
restituiscono l'elemento corrente dal file di testo comeString
. L'implementazione della proprietàCurrent
dell'interfacciaIEnumerator
può essere resaPrivate
, perché è necessario esporre solo i membri dell'interfacciaIEnumerator(Of String)
. Sostituire il codice generato da Visual Basic per le proprietàCurrent
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
Il metodo
MoveNext
dell'interfacciaIEnumerator
passa all'elemento successivo nel file di testo e aggiorna il valore restituito dalla proprietàCurrent
. Se non sono presenti altri elementi da leggere, il metodoMoveNext
restituisceFalse
. In caso contrario, il metodoMoveNext
restituisceTrue
. Aggiungere il codice seguente al metodoMoveNext
.Public Function MoveNext() As Boolean _ Implements System.Collections.IEnumerator.MoveNext _current = _sr.ReadLine() If _current Is Nothing Then Return False Return True End Function
Il metodo
Reset
dell'interfacciaIEnumerator
indirizza l'iteratore in modo che punti all'inizio del file di testo e cancella il valore dell'elemento corrente. Aggiungere il codice seguente al metodoReset
.Public Sub Reset() _ Implements System.Collections.IEnumerator.Reset _sr.DiscardBufferedData() _sr.BaseStream.Seek(0, IO.SeekOrigin.Begin) _current = Nothing End Sub
Il metodo
Dispose
dell'interfacciaIEnumerator
garantisce che tutte le risorse non gestite vengano rilasciate prima che l'iteratore venga eliminato definitivamente. L'handle di file usato dall'oggettoStreamReader
è 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 metodoDispose
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 ciclo For Next
o una query LINQ. Nell'esempio seguente viene illustrato StreamReaderEnumerable
in una query LINQ.
Dim adminRequests =
From line In New StreamReaderEnumerable("..\..\log.txt")
Where line.Contains("admin.aspx 401")
Dim results = adminRequests.ToList()