반복기 (Visual Basic)Iterators (Visual Basic)

반복기는 목록 및 배열과 같은 컬렉션을 단계별로 실행하는 데 사용할 수 있습니다.An iterator can be used to step through collections such as lists and arrays.

반복기 메서드 또는 get 접근자는 컬렉션에 대해 사용자 지정 반복을 수행합니다.An iterator method or get accessor performs a custom iteration over a collection. 반복기 메서드는 Yield 문을 사용 하 여 각 요소를 한 번에 하나씩 반환 합니다.An iterator method uses the Yield statement to return each element one at a time. Yield 문에 도달하면 코드의 현재 위치가 기억됩니다.When a Yield statement is reached, the current location in code is remembered. 다음에 반복기 함수가 호출되면 해당 위치에서 실행이 다시 시작됩니다.Execution is restarted from that location the next time the iterator function is called.

For Each ...를 사용 하 여 클라이언트 코드에서 반복기를 사용 합니다. 다음 문 또는 LINQ 쿼리 사용.You consume an iterator from client code by using a For Each…Next statement, or by using a LINQ query.

다음 예제에서 For Each 루프의 첫 번째 반복은 첫 번째 Yield 문에 도달할 때까지 SomeNumbers 반복기 메서드에서 실행이 계속되도록 합니다.In the following example, the first iteration of the For Each loop causes execution to proceed in the SomeNumbers iterator method until the first Yield statement is reached. 이 반복은 3 값을 반환하며 반복기 메서드에서 현재 위치는 유지됩니다.This iteration returns a value of 3, and the current location in the iterator method is retained. 루프의 다음 반복에서는 반복기 메서드의 실행이 중지되었던 위치에서 계속되고 Yield 문에 도달하면 다시 중지됩니다.On the next iteration of the loop, execution in the iterator method continues from where it left off, again stopping when it reaches a Yield statement. 이 반복은 값 5를 반환하며 반복기 메서드에서 현재 위치는 다시 유지됩니다.This iteration returns a value of 5, and the current location in the iterator method is again retained. 루프는 반복기 메서드의 끝에 도달하면 완료됩니다.The loop completes when the end of the iterator method is reached.

Sub Main()
    For Each number As Integer In SomeNumbers()
        Console.Write(number & " ")
    Next
    ' Output: 3 5 8
    Console.ReadKey()
End Sub

Private Iterator Function SomeNumbers() As System.Collections.IEnumerable
    Yield 3
    Yield 5
    Yield 8
End Function

반복기 메서드 또는 get 접근자의 반환 형식은 IEnumerable, IEnumerable<T>, IEnumerator 또는 IEnumerator<T>일 수 있습니다.The return type of an iterator method or get accessor can be IEnumerable, IEnumerable<T>, IEnumerator, or IEnumerator<T>.

@No__t_0 또는 Return 문을 사용 하 여 반복을 종료할 수 있습니다.You can use an Exit Function or Return statement to end the iteration.

Visual Basic iterator 함수 또는 get 접근자 선언에 반복기 한정자가 포함 되어 있습니다.A Visual Basic iterator function or get accessor declaration includes an Iterator modifier.

반복기는 Visual Studio 2012의 Visual Basic에서 도입 되었습니다.Iterators were introduced in Visual Basic in Visual Studio 2012.

항목 내용In this topic

참고

간단한 반복기 예를 제외 하 고 항목의 모든 예제에 대해 System.CollectionsSystem.Collections.Generic 네임 스페이스에 대 한 Imports 문을 포함 합니다.For all examples in the topic except the Simple Iterator example, include Imports statements for the System.Collections and System.Collections.Generic namespaces.

단순 반복기Simple Iterator

다음 예제에는 에 대 한 단일 Yield 문이 있습니다 ... Next 루프.The following example has a single Yield statement that is inside a For…Next loop. Main에서 For Each 문 본문을 반복할 때마다 다음 Yield 문으로 진행하는 반복기 함수에 대한 호출이 생성됩니다.In Main, each iteration of the For Each statement body creates a call to the iterator function, which proceeds to the next Yield statement.

Sub Main()
    For Each number As Integer In EvenSequence(5, 18)
        Console.Write(number & " ")
    Next
    ' Output: 6 8 10 12 14 16 18
    Console.ReadKey()
End Sub

Private Iterator Function EvenSequence(
ByVal firstNumber As Integer, ByVal lastNumber As Integer) _
As System.Collections.Generic.IEnumerable(Of Integer)

    ' Yield even numbers in the range.
    For number As Integer = firstNumber To lastNumber
        If number Mod 2 = 0 Then
            Yield number
        End If
    Next
End Function

컬렉션 클래스 만들기Creating a Collection Class

다음 예제에서 DaysOfTheWeek 클래스는 IEnumerable 인터페이스를 구현하며, GetEnumerator 메서드가 필요합니다.In the following example, the DaysOfTheWeek class implements the IEnumerable interface, which requires a GetEnumerator method. 컴파일러는 GetEnumerator 메서드를 암시적으로 호출하며, IEnumerator가 반환됩니다.The compiler implicitly calls the GetEnumerator method, which returns an IEnumerator.

@No__t_0 메서드는 Yield 문을 사용 하 여 각 문자열을 한 번에 하나씩 반환 하 고, Iterator 한정자는 함수 선언에 있습니다.The GetEnumerator method returns each string one at a time by using the Yield statement, and an Iterator modifier is in the function declaration.

Sub Main()
    Dim days As New DaysOfTheWeek()
    For Each day As String In days
        Console.Write(day & " ")
    Next
    ' Output: Sun Mon Tue Wed Thu Fri Sat
    Console.ReadKey()
End Sub

Private Class DaysOfTheWeek
    Implements IEnumerable

    Public days =
        New String() {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}

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

        ' Yield each day of the week.
        For i As Integer = 0 To days.Length - 1
            Yield days(i)
        Next
    End Function
End Class

다음 예제에서는 동물 컬렉션을 포함하는 Zoo 클래스를 만듭니다.The following example creates a Zoo class that contains a collection of animals.

클래스 인스턴스(theZoo)를 참조하는 For Each 문은 GetEnumerator 메서드를 암시적으로 호출합니다.The For Each statement that refers to the class instance (theZoo) implicitly calls the GetEnumerator method. BirdsMammals 속성을 참조하는 For Each 문은 AnimalsForType 명명된 반복기 메서드를 사용합니다.The For Each statements that refer to the Birds and Mammals properties use the AnimalsForType named iterator method.

Sub Main()
    Dim theZoo As New Zoo()

    theZoo.AddMammal("Whale")
    theZoo.AddMammal("Rhinoceros")
    theZoo.AddBird("Penguin")
    theZoo.AddBird("Warbler")

    For Each name As String In theZoo
        Console.Write(name & " ")
    Next
    Console.WriteLine()
    ' Output: Whale Rhinoceros Penguin Warbler

    For Each name As String In theZoo.Birds
        Console.Write(name & " ")
    Next
    Console.WriteLine()
    ' Output: Penguin Warbler

    For Each name As String In theZoo.Mammals
        Console.Write(name & " ")
    Next
    Console.WriteLine()
    ' Output: Whale Rhinoceros

    Console.ReadKey()
End Sub

Public Class Zoo
    Implements IEnumerable

    ' Private members.
    Private animals As New List(Of Animal)

    ' Public methods.
    Public Sub AddMammal(ByVal name As String)
        animals.Add(New Animal With {.Name = name, .Type = Animal.TypeEnum.Mammal})
    End Sub

    Public Sub AddBird(ByVal name As String)
        animals.Add(New Animal With {.Name = name, .Type = Animal.TypeEnum.Bird})
    End Sub

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

        For Each theAnimal As Animal In animals
            Yield theAnimal.Name
        Next
    End Function

    ' Public members.
    Public ReadOnly Property Mammals As IEnumerable
        Get
            Return AnimalsForType(Animal.TypeEnum.Mammal)
        End Get
    End Property

    Public ReadOnly Property Birds As IEnumerable
        Get
            Return AnimalsForType(Animal.TypeEnum.Bird)
        End Get
    End Property

    ' Private methods.
    Private Iterator Function AnimalsForType( _
    ByVal type As Animal.TypeEnum) As IEnumerable
        For Each theAnimal As Animal In animals
            If (theAnimal.Type = type) Then
                Yield theAnimal.Name
            End If
        Next
    End Function

    ' Private class.
    Private Class Animal
        Public Enum TypeEnum
            Bird
            Mammal
        End Enum

        Public Property Name As String
        Public Property Type As TypeEnum
    End Class
End Class

Try 블록Try Blocks

Try ...의 Try 블록에서 Yield 문을 허용 Visual Basic. Catch ... Finally 문.Visual Basic allows a Yield statement in the Try block of a Try...Catch...Finally Statement. @No__t_1 문을 포함 하는 Try 블록은 Catch 블록을 포함할 수 있으며 Finally 블록을 포함할 수 있습니다.A Try block that has a Yield statement can have Catch blocks, and can have a Finally block.

다음 예제에서는 반복기 함수에 Try, CatchFinally 블록을 포함 합니다.The following example includes Try, Catch, and Finally blocks in an iterator function. 반복기 함수의 Finally 블록은 For Each 반복이 완료 되기 전에 실행 됩니다.The Finally block in the iterator function executes before the For Each iteration finishes.

Sub Main()
    For Each number As Integer In Test()
        Console.WriteLine(number)
    Next
    Console.WriteLine("For Each is done.")

    ' Output:
    '  3
    '  4
    '  Something happened. Yields are done.
    '  Finally is called.
    '  For Each is done.
    Console.ReadKey()
End Sub

Private Iterator Function Test() As IEnumerable(Of Integer)
    Try
        Yield 3
        Yield 4
        Throw New Exception("Something happened. Yields are done.")
        Yield 5
        Yield 6
    Catch ex As Exception
        Console.WriteLine(ex.Message)
    Finally
        Console.WriteLine("Finally is called.")
    End Try
End Function

@No__t_0 문은 Catch 블록 또는 Finally 블록 안에 있을 수 없습니다.A Yield statement cannot be inside a Catch block or a Finally block.

반복기 메서드 대신 For Each 본문에서 예외를 throw 하는 경우 반복기 함수의 Catch 블록이 실행 되지 않지만 반복기 함수의 Finally 블록이 실행 됩니다.If the For Each body (instead of the iterator method) throws an exception, a Catch block in the iterator function is not executed, but a Finally block in the iterator function is executed. 반복기 함수 내의 Catch 블록은 반복기 함수 내에서 발생 하는 예외만 catch 합니다.A Catch block inside an iterator function catches only exceptions that occur inside the iterator function.

무명 메서드Anonymous Methods

Visual Basic에서 익명 함수는 반복기 함수 일 수 있습니다.In Visual Basic, an anonymous function can be an iterator function. 다음은 이에 대한 예입니다.The following example illustrates this.

Dim iterateSequence = Iterator Function() _
                      As IEnumerable(Of Integer)
                          Yield 1
                          Yield 2
                      End Function

For Each number As Integer In iterateSequence()
    Console.Write(number & " ")
Next
' Output: 1 2
Console.ReadKey()

다음 예제에는 인수의 유효성을 검사 하는 비 반복기 메서드가 있습니다.The following example has a non-iterator method that validates the arguments. 메서드는 컬렉션 요소를 설명 하는 익명 반복기의 결과를 반환 합니다.The method returns the result of an anonymous iterator that describes the collection elements.

Sub Main()
    For Each number As Integer In GetSequence(5, 10)
        Console.Write(number & " ")
    Next
    ' Output: 5 6 7 8 9 10
    Console.ReadKey()
End Sub

Public Function GetSequence(ByVal low As Integer, ByVal high As Integer) _
As IEnumerable
    ' Validate the arguments.
    If low < 1 Then
        Throw New ArgumentException("low is too low")
    End If
    If high > 140 Then
        Throw New ArgumentException("high is too high")
    End If

    ' Return an anonymous iterator function.
    Dim iterateSequence = Iterator Function() As IEnumerable
                              For index = low To high
                                  Yield index
                              Next
                          End Function
    Return iterateSequence()
End Function

유효성 검사가 반복기 함수 내에 있는 경우 For Each 본문의 첫 번째 반복이 시작 될 때까지 유효성 검사를 수행할 수 없습니다.If validation is instead inside the iterator function, the validation cannot be performed until the start of the first iteration of the For Each body.

제네릭 목록과 함께 반복기 사용Using Iterators with a Generic List

다음 예제에서 Stack(Of T) 제네릭 클래스는 IEnumerable<T> 제네릭 인터페이스를 구현합니다.In the following example, the Stack(Of T) generic class implements the IEnumerable<T> generic interface. Push 메서드는 T 형식의 배열에 값을 할당합니다.The Push method assigns values to an array of type T. GetEnumerator 메서드는 Yield 문을 사용하여 배열 값을 반환합니다.The GetEnumerator method returns the array values by using the Yield statement.

제네릭 GetEnumerator 메서드뿐 아니라 제네릭이 아닌 GetEnumerator 메서드도 구현해야 합니다.In addition to the generic GetEnumerator method, the non-generic GetEnumerator method must also be implemented. IEnumerable<T>IEnumerable에서 상속하기 때문입니다.This is because IEnumerable<T> inherits from IEnumerable. 제네릭이 아닌 구현은 제네릭 구현을 따릅니다.The non-generic implementation defers to the generic implementation.

예제에서는 명명된 반복기를 사용하여 동일한 데이터 컬렉션을 반복하는 다양한 방법을 지원합니다.The example uses named iterators to support various ways of iterating through the same collection of data. 이러한 명명된 반복기는 TopToBottomBottomToTop 속성과 TopN 메서드입니다.These named iterators are the TopToBottom and BottomToTop properties, and the TopN method.

@No__t_0 속성 선언에는 Iterator 키워드가 포함 됩니다.The BottomToTop property declaration includes the Iterator keyword.

Sub Main()
    Dim theStack As New Stack(Of Integer)

    ' Add items to the stack.
    For number As Integer = 0 To 9
        theStack.Push(number)
    Next

    ' Retrieve items from the stack.
    ' For Each is allowed because theStack implements
    ' IEnumerable(Of Integer).
    For Each number As Integer In theStack
        Console.Write("{0} ", number)
    Next
    Console.WriteLine()
    ' Output: 9 8 7 6 5 4 3 2 1 0

    ' For Each is allowed, because theStack.TopToBottom
    ' returns IEnumerable(Of Integer).
    For Each number As Integer In theStack.TopToBottom
        Console.Write("{0} ", number)
    Next
    Console.WriteLine()
    ' Output: 9 8 7 6 5 4 3 2 1 0

    For Each number As Integer In theStack.BottomToTop
        Console.Write("{0} ", number)
    Next
    Console.WriteLine()
    ' Output: 0 1 2 3 4 5 6 7 8 9

    For Each number As Integer In theStack.TopN(7)
        Console.Write("{0} ", number)
    Next
    Console.WriteLine()
    ' Output: 9 8 7 6 5 4 3

    Console.ReadKey()
End Sub

Public Class Stack(Of T)
    Implements IEnumerable(Of T)

    Private values As T() = New T(99) {}
    Private top As Integer = 0

    Public Sub Push(ByVal t As T)
        values(top) = t
        top = top + 1
    End Sub

    Public Function Pop() As T
        top = top - 1
        Return values(top)
    End Function

    ' This function implements the GetEnumerator method. It allows
    ' an instance of the class to be used in a For Each statement.
    Public Iterator Function GetEnumerator() As IEnumerator(Of T) _
        Implements IEnumerable(Of T).GetEnumerator

        For index As Integer = top - 1 To 0 Step -1
            Yield values(index)
        Next
    End Function

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

        Yield GetEnumerator()
    End Function

    Public ReadOnly Property TopToBottom() As IEnumerable(Of T)
        Get
            Return Me
        End Get
    End Property

    Public ReadOnly Iterator Property BottomToTop As IEnumerable(Of T)
        Get
            For index As Integer = 0 To top - 1
                Yield values(index)
            Next
        End Get
    End Property

    Public Iterator Function TopN(ByVal itemsFromTop As Integer) _
        As IEnumerable(Of T)

        ' Return less than itemsFromTop if necessary.
        Dim startIndex As Integer =
            If(itemsFromTop >= top, 0, top - itemsFromTop)

        For index As Integer = top - 1 To startIndex Step -1
            Yield values(index)
        Next
    End Function
End Class

구문 정보Syntax Information

반복기는 메서드 또는 get 접근자로 발생할 수 있습니다.An iterator can occur as a method or get accessor. 반복기는 이벤트, 인스턴스 생성자, 정적 생성자 또는 정적 소멸자에서 발생할 수 없습니다.An iterator cannot occur in an event, instance constructor, static constructor, or static destructor.

Yield 문의 식 형식에서 반복기의 반환 형식으로 암시적 변환이 있어야 합니다.An implicit conversion must exist from the expression type in the Yield statement to the return type of the iterator.

Visual Basic 반복기 메서드에는 ByRef 매개 변수를 사용할 수 없습니다.In Visual Basic, an iterator method cannot have any ByRef parameters.

Visual Basic에서 "Yield"는 예약 된 단어가 아니므로 Iterator 메서드나 get 접근자에서 사용 되는 경우에만 특별 한 의미가 있습니다.In Visual Basic, "Yield" is not a reserved word and has special meaning only when it is used in an Iterator method or get accessor.

기술 구현Technical Implementation

반복기를 메서드로 작성하는 경우에도 컴파일러는 실제로 상태 시스템인 중첩 클래스로 변환합니다.Although you write an iterator as a method, the compiler translates it into a nested class that is, in effect, a state machine. 이 클래스는 클라이언트 코드의 For Each...Next 루프가 계속되는 한 반복기의 위치를 추적합니다.This class keeps track of the position of the iterator as long the For Each...Next loop in the client code continues.

컴파일러의 용도를 확인하려면 Ildasm.exe 도구를 사용하여 반복기 메서드에 대해 생성되는 Microsoft Intermediate Language 코드를 확인할 수 있습니다.To see what the compiler does, you can use the Ildasm.exe tool to view the Microsoft intermediate language code that is generated for an iterator method.

클래스 또는 구조체에 대 한 반복기를 만들 때 전체 IEnumerator 인터페이스를 구현할 필요가 없습니다.When you create an iterator for a class or struct, you do not have to implement the whole IEnumerator interface. 컴파일러는 반복기를 검색할 경우 IEnumerator 또는 IEnumerator<T> 인터페이스의 Current, MoveNextDispose 메서드를 자동으로 생성합니다.When the compiler detects the iterator, it automatically generates the Current, MoveNext, and Dispose methods of the IEnumerator or IEnumerator<T> interface.

For Each…Next 루프를 연속 반복하거나 IEnumerator.MoveNext를 직접 호출하면 다음 반복기 코드 본문이 이전 Yield 문 다음에 다시 시작됩니다.On each successive iteration of the For Each…Next loop (or the direct call to IEnumerator.MoveNext), the next iterator code body resumes after the previous Yield statement. 그런 다음 반복기 본문의 끝에 도달 하거나 Exit Function 또는 Return 문이 발생할 때까지 다음 Yield 문으로 계속 합니다.It then continues to the next Yield statement until the end of the iterator body is reached, or until an Exit Function or Return statement is encountered.

반복기는 IEnumerator.Reset 메서드를 지원 하지 않습니다.Iterators do not support the IEnumerator.Reset method. 처음부터 다시 반복하려면 새 반복기를 가져와야 합니다.To re-iterate from the start, you must obtain a new iterator.

자세한 내용은 Visual Basic 언어 사양을 참조 하세요.For additional information, see the Visual Basic Language Specification.

반복기 사용Use of Iterators

반복기를 사용하면 복잡한 코드를 사용하여 목록 시퀀스를 채워야 하는 경우 For Each 루프의 단순성을 유지할 수 있습니다.Iterators enable you to maintain the simplicity of a For Each loop when you need to use complex code to populate a list sequence. 이 기능은 다음을 수행하려는 경우에 유용할 수 있습니다.This can be useful when you want to do the following:

  • 첫 번째 For Each 루프 반복 후 목록 시퀀스를 수정합니다.Modify the list sequence after the first For Each loop iteration.

  • 첫 번째 For Each 루프 반복 전에 큰 목록이 완전히 로드되지 않도록 합니다.Avoid fully loading a large list before the first iteration of a For Each loop. 한 가지 예로 테이블 행을 일괄 로드하는 페이징 페치가 있으며,An example is a paged fetch to load a batch of table rows. 또 다른 예로 .NET Framework 내에서 반복기를 구현하는 EnumerateFiles 메서드가 있습니다.Another example is the EnumerateFiles method, which implements iterators within the .NET Framework.

  • 반복기에서 목록 작성을 캡슐화합니다.Encapsulate building the list in the iterator. 반복기 메서드에서 목록을 빌드한 후 루프에서 각 결과를 생성할 수 있습니다.In the iterator method, you can build the list and then yield each result in a loop.

참조See also