yield 문 - 다음 요소 제공

반복기yield 에서 문을 사용하여 시퀀스를 반복할 때 시퀀스의 다음 값을 제공합니다. 문에는 yield 다음 두 가지 형식이 있습니다.

  • yield return: 다음 예제와 같이 반복에서 다음 값을 제공합니다.

    foreach (int i in ProduceEvenNumbers(9))
    {
        Console.Write(i);
        Console.Write(" ");
    }
    // Output: 0 2 4 6 8
    
    IEnumerable<int> ProduceEvenNumbers(int upto)
    {
        for (int i = 0; i <= upto; i += 2)
        {
            yield return i;
        }
    }
    
  • yield break: 다음 예제와 같이 반복의 끝을 명시적으로 신호로 표시합니다.

    Console.WriteLine(string.Join(" ", TakeWhilePositive(new[] { 2, 3, 4, 5, -1, 3, 4})));
    // Output: 2 3 4 5
    
    Console.WriteLine(string.Join(" ", TakeWhilePositive(new[] { 9, 8, 7 })));
    // Output: 9 8 7
    
    IEnumerable<int> TakeWhilePositive(IEnumerable<int> numbers)
    {
        foreach (int n in numbers)
        {
            if (n > 0)
            {
                yield return n;
            }
            else
            {
                yield break;
            }
        }
    }
    

    컨트롤이 반복기의 끝에 도달하면 반복도 완료됩니다.

앞의 예제에서 반복기의 반환 형식은 입니다 IEnumerable<T> (제네릭이 아닌 경우 반복기의 반환 형식으로 사용 IEnumerable ). 반복기의 반환 형식으로 를 사용할 IAsyncEnumerable<T> 수도 있습니다. 그러면 반복기 비동기가 만들어집니다. 다음 예제와 await foreach 같이 문을 사용하여 반복기의 결과를 반복합니다.

await foreach (int n in GenerateNumbersAsync(5))
{
    Console.Write(n);
    Console.Write(" ");
}
// Output: 0 2 4 6 8

async IAsyncEnumerable<int> GenerateNumbersAsync(int count)
{
    for (int i = 0; i < count; i++)
    {
        yield return await ProduceNumberAsync(i);
    }
}

async Task<int> ProduceNumberAsync(int seed)
{
    await Task.Delay(1000);
    return 2 * seed;
}

IEnumerator<T> 또는 IEnumerator 는 반복기의 반환 형식일 수도 있습니다. 이는 다음 시나리오에서 메서드를 구현할 GetEnumerator 때 유용합니다.

  • 또는 IEnumerable 인터페이스를 구현하는 형식을 디자인합니다IEnumerable<T>.

  • 다음 예제와 같이 문을 사용하여 형식의 인스턴스를 반복할 수 있도록 인스턴스 foreach또는 확장GetEnumerator 메서드를 추가합니다.

    public static void Example()
    {
        var point = new Point(1, 2, 3);
        foreach (int coordinate in point)
        {
            Console.Write(coordinate);
            Console.Write(" ");
        }
        // Output: 1 2 3
    }
    
    public readonly record struct Point(int X, int Y, int Z)
    {
        public IEnumerator<int> GetEnumerator()
        {
            yield return X;
            yield return Y;
            yield return Z;
        }
    }
    

다음에서 문을 사용할 yield 수 없습니다.

반복기 실행

반복기의 호출은 다음 예제와 같이 즉시 실행되지 않습니다.

var numbers = ProduceEvenNumbers(5);
Console.WriteLine("Caller: about to iterate.");
foreach (int i in numbers)
{
    Console.WriteLine($"Caller: {i}");
}

IEnumerable<int> ProduceEvenNumbers(int upto)
{
    Console.WriteLine("Iterator: start.");
    for (int i = 0; i <= upto; i += 2)
    {
        Console.WriteLine($"Iterator: about to yield {i}");
        yield return i;
        Console.WriteLine($"Iterator: yielded {i}");
    }
    Console.WriteLine("Iterator: end.");
}
// Output:
// Caller: about to iterate.
// Iterator: start.
// Iterator: about to yield 0
// Caller: 0
// Iterator: yielded 0
// Iterator: about to yield 2
// Caller: 2
// Iterator: yielded 2
// Iterator: about to yield 4
// Caller: 4
// Iterator: yielded 4
// Iterator: end.

앞의 예제에서 볼 수 있듯이 반복기의 결과를 반복하기 시작하면 첫 번째 yield return 문에 도달할 때까지 반복기가 실행됩니다. 그런 다음 반복기의 실행이 일시 중단되고 호출자가 첫 번째 반복 값을 가져오고 처리합니다. 이후의 각 반복에서 반복기의 실행은 이전 일시 중단을 yield return 발생시킨 문 이후에 다시 시작되고 다음 yield return 문에 도달할 때까지 계속됩니다. 컨트롤이 반복기 또는 문의 끝에 도달하면 반복이 yield break 완료됩니다.

C# 언어 사양

자세한 내용은 C# 언어 사양yield 문 섹션을 참조하세요.

참고 항목