Итераторы. Оператор Yield

Последнее обновление: 30.10.2015

Реализация интерфейса IEnumerable предполагает стандартную реализацию перечислителя. Однако мы можем не полагаться на стандартную реализацию, а создать свою логику итератора с помощью ключевых слов Iterator и Yield. Конструкция итератора представляет метод, в котором используется ключевое слово Yield для перебора по коллекции или массиву. Например, перепишем определенный в прошлой теме метод GetEnumerator в классе Library, применив итераторы:

Public Iterator Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator

    For i As Integer = 0 To books.Length - 1
        Yield books(i)
    Next

End Function

Метод GetEnumerator() теперь является итератором. И при переборе всех элементов в объекте Library через цикл For Each будет идти к обращение к вызову Yield books(i). При обращении к оператору Yield будет сохраняться текущее местоположение. И когда метод For Each перейдет к следующей итерации для получения нового объекта, итератор начнет выполнения с этого местоположения.

И в основной программе в цикле For Each стандартным образом:

For Each b As Book In library
    Console.WriteLine(b.Name)
Next

Хотя выше в методе GetEnumerator() применялся перебор массива в цикле for, но это необязательно делать. Можно просто определить несколько вызовов оператора Yield:

Public Iterator Function GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator

    Yield books(0)
    Yield books(1)
    Yield books(2)
End Function

Здесь также при вызове оператора Yield итератор запоминает текущее местоположение и при последующих вызовах начинает с него.

Именованный итератор

Хотя выше для создания итератора применялся метод GetEnumerator, но это необязательно, так как оператор Yield можно использовать внутри любого метода. Единственное ограничение - такой метод должен возвращать объект интерфейса IEnumerable. Подобные методы еще называют именованными итераторами.

Создадим такой именованный итератор в классе Library:

Class Book
    Public Property Name() As String
    Sub New(name As String)
        Me.Name = name
    End Sub
End Class
   
Class Library
    Dim books As Book()

    Sub New()
        books = New Book() {New Book("Отцы и дети"), New Book("Война и мир"),
            New Book("Евгений Онегин")}
    End Sub

    Public ReadOnly Property Length As Integer
        Get
            Return books.Length
        End Get

    End Property

    Default Public Property Item(index As Integer) As Book
        Get
            Return books(index)
        End Get
        Set(value As Book)
            books(index) = value
        End Set
    End Property

    Public Iterator Function GetBooks(max As Integer) As IEnumerable
        For i As Integer = 0 To max
            If i = books.Length Then
                Exit Function
            Else
                Yield books(i)
            End If
        Next
    End Function

End Class

Здесь в качестве итератора выступает функция Public Iterator Function GetBooks(max As Integer) As IEnumerable, которая принимает в качестве параметра количество выводимых объектов. В процессе работы программы может сложиться, что его значение будет больше, чем длина массива books. И чтобы не произошло ошибки, вызывается завершение функции с помощью операторов Exit Function.

Теперь применим итератор в программе:

Dim library As New Library()

For Each b As Book In library.GetBooks(5)
     Console.WriteLine(b.Name)
Next

Вызов library.GetBooks(5) возвращает набор из не более чем 5 объектов Book. Но поскольку по умолчанию объект library содержит всего три таких объекта, то в методе GetBooks после трех операций сработает завершение функции Exit Function.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850