Поделиться через


Пошаговое руководство. Реализация IEnumerable(Of T) в Visual Basic

Интерфейс 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, который у вас есть, и параметры, которые вы используете, определяют эти элементы. Дополнительные сведения см. в разделе Персонализация интегрированной среды разработки.

Создание класса Перечисляемый

Создание проекта перечисленного класса

  1. В Visual Basic в меню "Файл " наведите указатель мыши на "Создать " и нажмите кнопку "Проект".

  2. В диалоговом окне "Новый проект" в области "Типы проектов" убедитесь, что выбран Windows. Выберите библиотеку классов в области шаблонов . В поле "Имя" введите StreamReaderEnumerableи нажмите кнопку "ОК". Отображается новый проект.

  3. В обозревателе решений щелкните правой кнопкой мыши файл Class1.vb и нажмите кнопку "Переименовать". Переименуйте файл StreamReaderEnumerable.vb и нажмите клавишу ВВОД. Переименование файла также переименует класс в StreamReaderEnumerable. Этот класс реализует IEnumerable(Of String) интерфейс.

  4. Щелкните правой кнопкой мыши по проекту StreamReaderEnumerable, наведите указатель мыши на Добавить, а затем выберите Создать элемент. Выберите шаблон класса . В поле "Имя" введите StreamReaderEnumerator.vb и нажмите кнопку "ОК".

Первый класс в этом проекте — это перечислимый класс и будет реализовывать IEnumerable(Of String) интерфейс. Этот обобщенный интерфейс IEnumerable реализует интерфейс и гарантирует, что потребители этого класса могут получить доступ к значениям, типизированным как String.

Добавление кода для реализации IEnumerable

  1. Откройте файл StreamReaderEnumerable.vb.

  2. В строке после Public Class StreamReaderEnumerableвведите следующую команду и нажмите клавишу ВВОД.

    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введите следующую команду и нажмите клавишу ВВОД.

    Implements IEnumerator(Of String)
    

    Visual Basic автоматически заполняет класс элементами, необходимыми интерфейсом IEnumerator(Of String) .

  3. Класс перечислителя открывает текстовый файл и выполняет операции ввода-вывода для чтения строк из файла. Добавьте следующий код в класс, чтобы предоставить открытый конструктор, который принимает путь к файлу в качестве входного параметра и открыть текстовый файл для чтения.

    Private _sr As IO.StreamReader
    
    Public Sub New(ByVal filePath As String)
        _sr = New IO.StreamReader(filePath)
    End Sub
    
  4. Свойства Current для обоих IEnumerator(Of String)IEnumerator интерфейсов возвращают текущий элемент из текстового файла в виде String. Реализацию свойства 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
    
  5. Метод MoveNextIEnumerator интерфейса переходит к следующему элементу в текстовом файле и обновляет значение, возвращаемое свойством 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. Метод DisposeIEnumerator интерфейса гарантирует, что все неуправляемые ресурсы освобождаются до уничтожения итератора. Дескриптор файла, используемый 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()

См. также