본문 바로가기
C#

foreach() 순회 중 collection 변경은 예외 발생함

by Oz Driver 2025. 6. 29.

C# 에서 foreach() 문은 리스트나 배열 같은 컬렉션을 순회할 때 자주 사용됩니다.
코드가 간결하고 가독성도 좋기 때문에 선호되지만, 한 가지 중요한 제한이 있습니다.

 

foreach() 는 읽기 전용

foreach (var pb in listPB)
{
    if (IsCollision(pb, ball))
    {
        // 순회 중 컬렉션 변경 -> 예외 발생!!
        listPB.Remove(pb);
        break;
    }
}

 

겉보기에는 문제가 없어 보이지만, 이 코드는 실행 시 InvalidOperationException 예외를 발생시킵니다.
foreach()는 내부적으로 열거자(Enumerator) 를 사용하기 때문에, 순회 중 컬렉션이 변경되면 예외를 던지게 되어 있습니다. break 로 바로 빠져나온다 해도 이미 순회 중에 Remove()가 실행되었기 때문에 위험한 코드입니다.

 

컬렉션을 수정하려면 for() 문으로 순회

따라서 컬렉션을 수정해야 하는 경우는 반드시 for() 문을 사용해야 합니다.

for( int i = 0; i < listPB.Count; i++)
{    
    if (IsCollision(listPB[i], ball))
    {
        listPB.RemoveAt(i);
        break;
    }
}

 

이 방식은 안전하게 작동하지만, 한 가지 주의할 점이 있습니다.
RemoveAt()을 하면 리스트의 뒤 요소들이 한 칸씩 앞으로 당겨지기 때문에, 인덱스를 증가시키는 구조에서는 다음 요소를 건너뛸 수 있습니다.

 

for() 문으로 순회 중, 여러 개를 삭제해야 한다면, 역방향으로 

for (int i = listPB.Count - 1; i >= 0; i--)
{
    if (IsCollision(listPB[i], ball))
    {
        listPB.RemoveAt(i);
    }
}

 

위와 같이 끝에서부터 역방향으로 순회하면, 삭제 후 요소가 앞으로 당겨지더라도 이미 지난 인덱스들이므로 영향을 받지 않습니다.

 

정리

• 순회 중 삭제가 없다면 : foreach() 

• 순회 중 1개를 삭제해야 한다면 : for() 순방향 또는 역방향

• 순회 중 2개 이상을 삭제해야 한다면 : for() 역방향

 

 

 

'C#' 카테고리의 다른 글

bool = 조건식 과 삼항 연산자  (0) 2025.06.29
C# 의 Interface 기초부터 활용까지  (1) 2025.06.26
C#의 is 와 as 키워드 (#02)  (0) 2025.06.26
C#의 is 와 as 키워드 (#01)  (0) 2025.06.26
C# 의 상속이 C++ 과 다른 점  (0) 2025.06.25