Пошаговое руководство. Реализация 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 и используемых параметров. Дополнительные сведения см. в разделе Персонализация среды IDE.
Создание класса Перечисления
Создание проекта перечисленного класса
В Visual Basic в меню "Файл " наведите указатель мыши на "Создать " и нажмите кнопку "Проект".
Убедитесь, что в диалоговом окне Создание проекта в области Типы проектов выбран пункт Windows. Выберите Библиотеки классов в области Шаблоны. В поле Имя введите
StreamReaderEnumerable
и нажмите кнопку ОК. Отображается новый проект.В Обозреватель решений щелкните правой кнопкой мыши файл Class1.vb и нажмите кнопку "Переименовать". Измените имя файла на
StreamReaderEnumerable.vb
и нажмите клавишу ВВОД. При переименовании файла класс также будет переименован вStreamReaderEnumerable
. Этот класс реализует интерфейсIEnumerable(Of String)
.Щелкните правой кнопкой мыши проект StreamReaderEnumerable, наведите указатель мыши на добавление и выберите пункт "Создать элемент". Выберите шаблон класса. В поле Имя введите
StreamReaderEnumerator.vb
, а затем нажмите кнопку ОК.
Первый класс в этом проекте — это перечислимый класс и будет реализовывать IEnumerable(Of String)
интерфейс. Этот универсальный IEnumerable интерфейс реализует интерфейс и гарантирует, что потребители этого класса могут получить доступ к значениям, типизированным как String
.
Добавление кода для реализации IEnumerable
Откройте файл StreamReaderEnumerable.vb.
В строке после
Public Class StreamReaderEnumerable
введите следующую команду и нажмите клавишу ВВОД.Implements IEnumerable(Of String)
Visual Basic автоматически заполняет класс элементами, необходимыми интерфейсом
IEnumerable(Of String)
.Этот перечисленный класс будет считывать строки из текстового файла по одной строке за раз. Добавьте следующий код в класс, чтобы предоставить открытый конструктор, который принимает путь к файлу в качестве входного параметра.
Private _filePath As String Public Sub New(ByVal filePath As String) _filePath = filePath End Sub
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
Откройте файл StreamReaderEnumerator.vb.
В строке после
Public Class StreamReaderEnumerator
введите следующую команду и нажмите клавишу ВВОД.Implements IEnumerator(Of String)
Visual Basic автоматически заполняет класс элементами, необходимыми интерфейсом
IEnumerator(Of String)
.Класс перечислителя открывает текстовый файл и выполняет операции ввода-вывода для чтения строк из файла. Добавьте следующий код в класс, чтобы предоставить открытый конструктор, который принимает путь к файлу в качестве входного параметра и открыть текстовый файл для чтения.
Private _sr As IO.StreamReader Public Sub New(ByVal filePath As String) _sr = New IO.StreamReader(filePath) End Sub
Свойства
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
Метод
MoveNext
IEnumerator
интерфейса переходит к следующему элементу в текстовом файле и обновляет значение, возвращаемое свойствомCurrent
. Если для чтения отсутствуют элементы, метод возвращаетсяFalse
; в противном случаеMoveNext
метод возвращаетсяTrue
.MoveNext
Добавьте следующий код в метод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
Метод
Reset
IEnumerator
интерфейса направляет итератор, указывающий на начало текстового файла и очищает текущее значение элемента. Добавьте следующий код в методReset
.Public Sub Reset() _ Implements System.Collections.IEnumerator.Reset _sr.DiscardBufferedData() _sr.BaseStream.Seek(0, IO.SeekOrigin.Begin) _current = Nothing End Sub
Метод
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
Использование итератора примера
Класс перечисления можно использовать вместе со структурами управления, для которых требуется объект, For Next
реализующий IEnumerable
цикл или запрос LINQ. В следующем примере показан StreamReaderEnumerable
запрос LINQ.
Dim adminRequests =
From line In New StreamReaderEnumerable("..\..\log.txt")
Where line.Contains("admin.aspx 401")
Dim results = adminRequests.ToList()