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 int[] {2, 3, 4, 5, -1, 3, 4}))); // Output: 2 3 4 5 Console.WriteLine(string.Join(" ", TakeWhilePositive(new int[] {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<T> 또는 IEnumerable 인터페이스를 구현하는 형식을 디자인합니다.
다음 예제와 같이 을 사용하여 형식 인스턴스를 반복할 수 있도록 인스턴스 또는
GetEnumerator
foreach
메서드를 추가합니다.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
문을 사용할 수 없습니다.
- in, ref 또는 out 매개 변수가 있는 메서드입니다.
- 람다 식 및익명 메서드.
-
안전하지 않은 블록. C# 13 이전에는
yield
블록이 있는 모든 메서드에서unsafe
가 유효하지 않습니다. C# 13부터는yield
를unsafe
블록이 있는 메서드에서는 사용할 수 있지만unsafe
블록에서는 사용할 수 없습니다. -
yield return
catch 및yield break
finally 및 문은yield return
블록이 없고yield break
블록만 있는try
블록에서catch
사용할 수finally
있습니다.
using
반복기의 문
반복기 메서드에서 문을 사용할 using
수 있습니다.
using
문은 절이 있는 블록(finally
및 블록 없음catch
)으로 try
컴파일되므로 반복기에서 올바르게 작동합니다. 삭제 가능한 리소스는 반복기의 실행 전체에서 올바르게 관리됩니다.
Console.WriteLine("=== Using in Iterator Example ===");
// Demonstrate that using statements work correctly in iterators
foreach (string line in ReadLinesFromResource())
{
Console.WriteLine($"Read: {line}");
// Simulate processing only first two items
if (line == "Line 2") break;
}
Console.WriteLine("Iteration stopped early - resource should still be disposed.");
static IEnumerable<string> ReadLinesFromResource()
{
Console.WriteLine("Opening resource...");
using var resource = new StringWriter(); // Use StringWriter as a simple IDisposable
resource.WriteLine("Resource initialized");
// These lines would typically come from the resource (e.g., file, database)
string[] lines = { "Line 1", "Line 2", "Line 3", "Line 4" };
foreach (string line in lines)
{
Console.WriteLine($"About to yield: {line}");
yield return line;
Console.WriteLine($"Resumed after yielding: {line}");
}
Console.WriteLine("Iterator completed - using block will dispose resource.");
}
앞의 예제에서와 같이 반복기가 문에서 using
실행을 일시 중단하고 다시 시작하는 경우에도 문에서 획득한 리소스는 반복기의 실행 전체에서 yield return
계속 사용할 수 있습니다. 반복기가 완료될 때(끝에 도달하거나 통해 yield break
) 또는 반복기 자체가 삭제될 때(예: 호출자가 열거형이 일찍 중단되는 경우) 리소스가 삭제됩니다.
반복기 실행
다음 예제와 같이 반복기의 호출은 즉시 실행되지 않습니다.
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 문 섹션을 참조하세요.
참고 항목
.NET