반복 문 - for, foreach, do, while

반복 문은 명령문 또는 명령문 블록을 반복적으로 실행합니다. for: 지정된 부울 식이 true로 계산되는 동안 본문을 실행합니다. foreach: 컬렉션의 요소를 열거하고 컬렉션의 각 요소에 대한 본문을 실행합니다. do: 조건에 따라 본문을 한 번 이상 실행합니다. while: 조건에 따라 본문을 0번 이상 실행합니다.

반복 문 내의 어느 지점에서나 break을 사용하여 루프를 중단할 수 있습니다. continue을 사용하여 루프에서 다음 반복으로 이동할 수 있습니다.

for

for 문은 지정된 부울 식이 true로 계산되는 동안 문 또는 문 블록을 실행합니다. 다음 예제에서는 정수 카운터가 3보다 작으므로 본문을 실행하는 for 문을 보여 줍니다.

for (int i = 0; i < 3; i++)
{
    Console.Write(i);
}
// Output:
// 012

위의 예제에서는 for 문의 요소를 보여 줍니다.

  • 루프로 유입되기 전에 한 번만 실행되는 initializer 섹션입니다. 일반적으로 해당 섹션에서 로컬 루프 변수를 선언하고 초기화합니다. 선언된 변수는 for 문 외부에서 액세스할 수 없습니다.

    앞의 예제에서 이니셜라이저 섹션은 정수 카운터 변수를 선언하고 초기화합니다.

    int i = 0
    
  • 루프의 다음 반복을 실행할지 여부를 결정하는 condition 섹션입니다. 이 결과가 true이거나 없으면 다음 반복이 실행되고, 그렇지 않으면 루프가 종료됩니다. condition 섹션은 부울 식이어야 합니다.

    앞의 예제에서 condition 섹션은 카운터 값이 3보다 적은지 확인합니다.

    i < 3
    
  • 루프의 본문을 실행할 때마다 수행되는 작업을 정의하는 iterator 섹션입니다.

    앞의 예제에서 iterator 섹션은 카운터를 증가시킵니다.

    i++
    
  • 루프의 본문은 명령문 또는 명령문의 블록입니다.

iterator 섹션에는 쉼표로 구분된 다음 명령문 식이 0개 이상 포함될 수 있습니다.

initializer 섹션에서 루프 변수를 선언하지 않는 경우 initializer 섹션의 이전 목록에서 0개 이상의 식을 사용할 수 있습니다. 다음 예제에서는 initializer 섹션에서 외부 변수에 값 할당, initializer 및 iterator 섹션에서 메서드 호출, iterator 섹션에서 두 변수의 값 변경과 같이 initializer 및 iterator 섹션의 여러 가지 덜 일반적인 사용법을 보여 줍니다.

int i;
int j = 3;
for (i = 0, Console.WriteLine($"Start: i={i}, j={j}"); i < j; i++, j--, Console.WriteLine($"Step: i={i}, j={j}"))
{
    //...
}
// Output:
// Start: i=0, j=3
// Step: i=1, j=2
// Step: i=2, j=1

for 문의 모든 섹션은 선택 사항입니다. 예를 들어 다음 코드는 무한 for 루프를 정의합니다.

for ( ; ; )
{
    //...
}

foreach

foreach 문은 다음 예제와 같이 System.Collections.IEnumerable 또는 System.Collections.Generic.IEnumerable<T> 인터페이스를 구현하는 형식의 인스턴스에 있는 각 요소에 대해 문 또는 문 블록을 실행합니다.

List<int> fibNumbers = [0, 1, 1, 2, 3, 5, 8, 13];
foreach (int element in fibNumbers)
{
    Console.Write($"{element} ");
}
// Output:
// 0 1 1 2 3 5 8 13

foreach 문은 이러한 형식으로 제한되지 않습니다. 다음 조건을 충족하는 모든 형식의 인스턴스와 함께 사용할 수 있습니다.

  • 형식에 public 매개 변수가 없는 GetEnumerator 메서드가 있습니다. GetEnumerator 메서드는 형식의 확장 메서드일 수 있습니다.
  • GetEnumerator 메서드의 반환 형식이 public Current 속성과 반환 형식이 bool인 public 매개 변수가 없는 MoveNext 메서드를 포함합니다.

다음 예제에서는 인터페이스를 구현하지 않는 System.Span<T> 형식의 인스턴스와 함께 foreach 문을 사용합니다.

Span<int> numbers = [3, 14, 15, 92, 6];
foreach (int number in numbers)
{
    Console.Write($"{number} ");
}
// Output:
// 3 14 15 92 6

열거자의 Current 속성이 참조 반환 값(ref T 여기서 T는 컬렉션 요소의 형식임)을 반환하는 경우 다음 예제와 같이 ref 또는 ref readonly 한정자를 사용하여 반복 변수를 선언할 수 있습니다.

Span<int> storage = stackalloc int[10];
int num = 0;
foreach (ref int item in storage)
{
    item = num++;
}
foreach (ref readonly var item in storage)
{
    Console.Write($"{item} ");
}
// Output:
// 0 1 2 3 4 5 6 7 8 9

foreach 문의 소스 컬렉션이 비어 있으면 foreach 문의 본문이 실행되지 않고 건너뜁니다. foreach 문이 null에 적용되면 NullReferenceException이 throw됩니다.

await foreach

await foreach 문을 사용하여 비동기 데이터 스트림 즉, IAsyncEnumerable<T> 인터페이스를 구현하는 컬렉션 형식을 사용할 수 있습니다. 루프의 각 반복은 다음 요소가 비동기적으로 검색되는 동안 일시 중단될 수도 있습니다. 다음 예제에서는 await foreach 문을 사용하는 방법을 보여줍니다.

await foreach (var item in GenerateSequenceAsync())
{
    Console.WriteLine(item);
}

다음 조건을 충족하는 모든 형식의 인스턴스와 함께 await foreach 문을 사용할 수도 있습니다.

  • 형식에 public 매개 변수가 없는 GetAsyncEnumerator 메서드가 있습니다. 해당 메서드는 형식의 확장 메서드일 수 있습니다.
  • GetAsyncEnumerator 메서드의 반환 형식에는 public Current 속성과 반환 형식이 Task<bool>, ValueTask<bool> 또는 awaiter의 GetResult 메서드가 bool 값을 반환하는 다른 모든 대기 가능 형식이 포함된 public 매개 변수가 없는 MoveNextAsync 메서드가 있습니다.

기본적으로 스트림 요소는 캡처된 컨텍스트에서 처리됩니다. 컨텍스트 캡처를 사용하지 않도록 설정하려면 TaskAsyncEnumerableExtensions.ConfigureAwait 확장 메서드를 사용합니다. 동기화 컨텍스트 및 현재 컨텍스트 캡처에 대한 자세한 내용은 작업 기반 비동기 패턴 사용을 참조하세요. 비동기 스트림에 대한 자세한 내용은 비동기 스트림 자습서를 참조하세요.

반복 변수의 형식

다음 코드와 같이 var 키워드를 사용하여 컴파일러가 foreach 문에서 반복 변수의 형식을 유추할 수 있습니다.

foreach (var item in collection) { }

참고 항목

var 형식은 null 허용 인식 컨텍스트가 사용하도록 설정되었는지 여부와 초기화 식의 형식이 참조 형식인지 여부에 따라 컴파일러에서 null 허용 참조 형식으로 유추될 수 있습니다. 자세한 내용은 암시적으로 형식화된 지역 변수를 참조하세요.

다음 코드와 같이 반복 변수의 형식을 명시적으로 지정할 수도 있습니다.

IEnumerable<T> collection = new T[5];
foreach (V item in collection) { }

위의 양식에서 컬렉션 요소의 T 형식은 암시적 또는 명시적으로 반복 변수의 V 형식으로 변환할 수 있어야 합니다. T에서 V로의 명시적 변환이 런타임에 실패하는 경우 foreach 문은 InvalidCastException을 throw합니다. 예를 들어 T가 봉인되지 않은 클래스 형식인 경우 VT가 구현하지 않는 형식을 포함하여 모든 인터페이스 형식일 수 있습니다. 런타임에 컬렉션 요소의 형식은 T에서 파생되어 실제로 V를 구현하는 형식일 수 있습니다. 그렇지 않은 경우에는 InvalidCastException을 throw합니다.

do

do 문은 지정된 부울 식이 true로 계산되는 동안 문 또는 문 블록을 실행합니다. 이 식은 각 루프 실행 후 평가되기 때문에 do 루프가 한 번 이상 실행됩니다. do 루프는 0회 이상 실행되는 while 루프와 다릅니다.

다음 예제에서는 do 문의 사용량을 보여 줍니다.

int n = 0;
do
{
    Console.Write(n);
    n++;
} while (n < 5);
// Output:
// 01234

while

while 문은 지정된 부울 식이 true로 계산되는 동안 문 또는 문 블록을 실행합니다. 이 식은 각 루프를 실행하기 전에 평가되기 때문에 while 루프는 0번 이상 실행됩니다. while 루프는 한 번 이상 실행되는 do 루프와 다릅니다.

다음 예제에서는 while 문의 사용량을 보여 줍니다.

int n = 0;
while (n < 5)
{
    Console.Write(n);
    n++;
}
// Output:
// 01234

C# 언어 사양

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

이러한 기능에 대한 자세한 내용은 다음 기능 제안 노트를 참조하세요.

참고 항목