Wskazówki: wdrażanie IEnumerable(Of T) w Visual Basic

Interfejs IEnumerable<T> jest implementowany przez klasy, które mogą zwracać sekwencję wartości jeden element naraz. Zaletą zwracania danych w danym momencie jest to, że nie trzeba ładować pełnego zestawu danych do pamięci, aby z nim pracować. Wystarczy użyć wystarczającej ilości pamięci, aby załadować pojedynczy element z danych. Klasy implementujące IEnumerable(T) interfejs mogą być używane z pętlami For Each lub zapytaniami LINQ.

Rozważmy na przykład aplikację, która musi odczytać duży plik tekstowy i zwrócić każdy wiersz z pliku, który spełnia określone kryteria wyszukiwania. Aplikacja używa zapytania LINQ do zwracania wierszy z pliku, które spełniają określone kryteria. Aby zbadać zawartość pliku przy użyciu zapytania LINQ, aplikacja może załadować zawartość pliku do tablicy lub kolekcji. Jednak załadowanie całego pliku do tablicy lub kolekcji zużywałoby znacznie więcej pamięci niż jest to wymagane. Zapytanie LINQ może zamiast tego wykonywać zapytania dotyczące zawartości pliku przy użyciu klasy wyliczalnej, zwracając tylko wartości spełniające kryteria wyszukiwania. Zapytania zwracające tylko kilka pasujących wartości zużywają znacznie mniej pamięci.

Możesz utworzyć klasę, która implementuje IEnumerable<T> interfejs w celu uwidaczniania danych źródłowych jako danych wyliczalnych. Klasa, która implementuje IEnumerable(T) interfejs, będzie wymagać innej klasy, która implementuje IEnumerator<T> interfejs do iterowania danych źródłowych. Te dwie klasy umożliwiają sekwencyjne zwracanie elementów danych jako określonego typu.

W tym przewodniku utworzysz klasę, która implementuje interfejs i klasę, która implementuje IEnumerable(Of String)IEnumerator(Of String) interfejs w celu odczytania pliku tekstowego po jednym wierszu naraz.

Uwaga

Na komputerze w poniższych instrukcjach mogą być wyświetlane inne nazwy i lokalizacje niektórych elementów interfejsu użytkownika programu Visual Studio. Te elementy są określane przez numer wersji Visual Studio oraz twoje ustawienia. Aby uzyskać więcej informacji, zobacz Personalizowanie środowiska IDE.

Tworzenie klasy Enumerable

Tworzenie projektu klasy wyliczalnej

  1. W języku Visual Basic w menu Plik wskaż polecenie Nowy , a następnie kliknij pozycję Projekt.

  2. W oknie dialogowym Nowy projekt w okienku Typy projektów upewnij się, że wybrano pozycję Windows. Wybierz pozycję Biblioteka klas w okienku Szablony . W polu Nazwa wpisz StreamReaderEnumerable, a następnie kliknij przycisk OK. Zostanie wyświetlony nowy projekt.

  3. W Eksplorator rozwiązań kliknij prawym przyciskiem myszy plik Class1.vb i kliknij polecenie Zmień nazwę. Zmień nazwę pliku na StreamReaderEnumerable.vb i naciśnij klawisz ENTER. Zmiana nazwy pliku spowoduje również zmianę nazwy klasy na StreamReaderEnumerable. Ta klasa zaimplementuje IEnumerable(Of String) interfejs.

  4. Kliknij prawym przyciskiem myszy projekt StreamReaderEnumerable, wskaż polecenie Dodaj, a następnie kliknij pozycję Nowy element. Wybierz szablon Klasa. W polu Nazwa wpisz StreamReaderEnumerator.vb i kliknij przycisk OK.

Pierwszą klasą w tym projekcie jest klasa wyliczalna i zaimplementuje IEnumerable(Of String) interfejs. Ten interfejs ogólny implementuje IEnumerable interfejs i gwarantuje, że użytkownicy tej klasy mogą uzyskać dostęp do wartości wpisanych jako String.

Dodawanie kodu w celu zaimplementowania funkcji IEnumerable

  1. Otwórz plik StreamReaderEnumerable.vb.

  2. W wierszu po Public Class StreamReaderEnumerablewpisz następujący tekst i naciśnij klawisz ENTER.

    Implements IEnumerable(Of String)
    

    Program Visual Basic automatycznie wypełnia klasę elementami członkowskimi wymaganymi przez IEnumerable(Of String) interfejs.

  3. Ta klasa wyliczalna odczytuje wiersze z pliku tekstowego po jednym wierszu naraz. Dodaj następujący kod do klasy, aby uwidocznić publiczny konstruktor, który przyjmuje ścieżkę pliku jako parametr wejściowy.

    Private _filePath As String
    
    Public Sub New(ByVal filePath As String)
        _filePath = filePath
    End Sub
    
  4. Implementacja GetEnumerator metody interfejsu IEnumerable(Of String) zwróci nowe wystąpienie StreamReaderEnumerator klasy. Implementację GetEnumerator metody interfejsu IEnumerable można wykonać Private, ponieważ trzeba uwidocznić tylko elementy członkowskie interfejsu IEnumerable(Of String) . Zastąp kod wygenerowany w języku Visual Basic dla GetEnumerator metod następującym kodem.

    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
    

Dodawanie kodu w celu zaimplementowania modułu IEnumerator

  1. Otwórz plik StreamReaderEnumerator.vb.

  2. W wierszu po Public Class StreamReaderEnumeratorwpisz następujący tekst i naciśnij klawisz ENTER.

    Implements IEnumerator(Of String)
    

    Program Visual Basic automatycznie wypełnia klasę elementami członkowskimi wymaganymi przez IEnumerator(Of String) interfejs.

  3. Klasa modułu wyliczającego otwiera plik tekstowy i wykonuje operacje we/wy pliku w celu odczytania wierszy z pliku. Dodaj następujący kod do klasy, aby uwidocznić publiczny konstruktor, który przyjmuje ścieżkę pliku jako parametr wejściowy, a następnie otwórz plik tekstowy do odczytu.

    Private _sr As IO.StreamReader
    
    Public Sub New(ByVal filePath As String)
        _sr = New IO.StreamReader(filePath)
    End Sub
    
  4. Właściwości Current dla interfejsów IEnumerator(Of String) i IEnumerator zwracają bieżący element z pliku tekstowego jako String. Implementację Current właściwości IEnumerator interfejsu można wykonać Private, ponieważ trzeba uwidocznić tylko elementy członkowskie interfejsu IEnumerator(Of String) . Zastąp kod wygenerowany przez program Visual Basic dla Current właściwości następującym kodem.

    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. Metoda MoveNext interfejsu IEnumerator przechodzi do następnego elementu w pliku tekstowym i aktualizuje wartość zwracaną przez Current właściwość . Jeśli nie ma więcej elementów do odczytania MoveNext , metoda zwraca Falsewartość ; w przeciwnym razie MoveNext metoda zwraca Truewartość . Dodaj następujący kod do metody 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. Metoda Reset interfejsu IEnumerator kieruje iterator, aby wskazywał początek pliku tekstowego i czyści bieżącą wartość elementu. Dodaj następujący kod do metody Reset:

    Public Sub Reset() _
        Implements System.Collections.IEnumerator.Reset
    
        _sr.DiscardBufferedData()
        _sr.BaseStream.Seek(0, IO.SeekOrigin.Begin)
        _current = Nothing
    End Sub
    
  7. Metoda Dispose interfejsu IEnumerator gwarantuje, że wszystkie niezarządzane zasoby zostaną zwolnione przed zniszczeniem iteratora. Uchwyt pliku używany przez StreamReader obiekt jest zasobem niezarządzanym i musi zostać zamknięty przed zniszczeniem wystąpienia iteratora. Zastąp kod wygenerowany przez program Visual Basic dla Dispose metody następującym kodem.

    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
    

Korzystanie z iteratora przykładowego

Można użyć klasy wyliczalnej w kodzie wraz ze strukturami sterującymi, które wymagają obiektu implementujące IEnumerableobiekt , taki jak pętla For Next lub zapytanie LINQ. W poniższym przykładzie pokazano StreamReaderEnumerable element w zapytaniu LINQ.

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

Dim results = adminRequests.ToList()

Zobacz też