홈으로 돌아가기

C# 15의 레이블된 break: 실전 적용

이 기사는 C# 15의 레이블된 break와 continue 기능의 실전 가치를 분석합니다. 실제 사용 시나리오, 대안과의 비교, 미들/시니어 수준 개발자를 위한 사용 추천을 다룹니다.

C# 15의 레이블된 break: 사용 가치가 있을까?
Advertisement 728x90

C# 15의 레이블된 break와 continue: 새로운 루프 레이블을 언제, 왜 사용해야 할까

C# 15에서 오랫동안 기다려온 하지만 논쟁적인 기능—레이블된 break와 continue가 도입되었습니다. 커뮤니티 일부의 비판에도 불구하고, 이 기능은 중첩 루프와 switch 표현식을 다룰 때 발생하는 구체적인 문제를 해결합니다. 특히 goto나 플래그를 사용하지 않고 가장 안쪽 블록이 아닌 외부 루프를 종료해야 하는 경우에 특히 적합합니다.

중첩 구조에서 탈출하는 문제

전통적으로 C#에서는 break나 continue 문을 사용할 때 탈출할 루프를 명시적으로 지정할 수 없었습니다. 이로 인해 추가 논리 플래그를 도입하거나 코드를 메서드로 분리하거나 goto를 사용해야 했는데, 이는 깨끗한 코드 원칙에 어긋납니다. 예를 들어 2차원 데이터 구조를 처리할 때 특정 조건을 만족하면 모든 반복을 즉시 중단해야 하는 경우가 많습니다:

string foundValue = null;
bool shouldBreak = false;

for (int x = 0; x < xMax; x++)
{
    for (int y = 0; y < yMax; y++)
    {
        foundValue = GetValue(x, y);

        if (foundValue == targetValue)
        {
            shouldBreak = true;
            break;
        }
    }

    if (shouldBreak)
    {
        break;
    }
}

ProcessValue(foundValue);

이 접근 방식은 코드를 지저분하게 만들 뿐만 아니라 오류 발생 위험도 초래합니다—예를 들어 값이 발견되지 않았는데도 ProcessValue를 호출하는 실수입니다. 로직을 별도 메서드로 추출하는 대안은 가독성을 높이지만, 루프 상태가 여러 외부 변수에 의존할 때는 항상 적용하기 어렵습니다.

Google AdInline article slot

레이블된 break/continue의 실제 사용 사례

레이블을 사용하는 가장 설득력 있는 경우는 루프 안의 switch 작업입니다. 레이블된 break가 없으면 case 분기 안에서 외부 루프를 종료할 수 없습니다. 이전에는 goto를 사용하거나 로직을 람다/로컬 함수로 감싸야 했습니다. 이제는 간단합니다:

outer: foreach (var item in collection)
{
    switch (item.Type)
    {
        case ItemType.StopAll:
            break outer;
        case ItemType.SkipGroup:
            continue outer;
    }
}

이런 코드는 의도를 명확히 표현합니다: break outer는 전체 루프를 종료하고, continue outer는 외부 루프의 다음 반복으로 건너뜁니다. 이는 파서, 유한 상태 기계, 이벤트 라우팅 시스템에서 특히 유용합니다.

레이블을 피해야 할 때

기술적으로 올바르긴 하지만, 레이블된 break와 continue를 어디서나 사용해서는 안 됩니다. 대안을 사용했을 때 가독성이나 성능이 악화되는 상황에서만 정당화됩니다. 대부분의 경우 다음을 우선하세요:

Google AdInline article slot
  • 조기 반환(early return)을 사용한 별도 메서드로 로직 추출.
  • 값 찾기에 LINQ 연산자(FirstOrDefault, Any 등) 사용.
  • 단순한 중첩 구조에서만 플래그 사용.

레이블이 정당화되는 경우:

  • 루프 안에 외부 루프 수준의 흐름 제어가 필요한 많은 case가 있는 switch가 포함된 경우.
  • 성능이 중요하고 메서드 추출로 인한 오버헤드를 피하고 싶은 경우.
  • 의미적 무결성을 잃지 않고 로직을 분해할 수 없는 경우.

접근 방식 비교: 레이블 vs. 리팩토링

행렬에서 값을 검색하면서 행 건너뛰기와 조기 종료가 가능한 동일 시나리오를 세 가지 방식으로 구현해 보겠습니다:

Approach 1: Flags

Google AdInline article slot

— 장점: 모든 C# 버전과 호환.

— 단점: 높은 인지 복잡도, 오류 위험.

Approach 2: 메서드로 분리

— 장점: 가독성, 테스트 용이성, SOLID 원칙 준수.

— 단점: 호출 스택 깊이 증가 가능.

Approach 3: 레이블된 break/continue

— 장점: 컴팩트함, 의도 정확한 표현.

— 단점: 적용 범위 제한, 일부 개발자 낯설음.

선택은 맥락에 달려 있습니다. 비즈니스 로직에는 접근 방식 2를, 시스템 코드나 파서에는 접근 방식 3을 우선하세요.

주요 포인트

  • C# 15의 레이블된 break와 continue는 좁지만 실제적인 문제를 해결합니다: 중첩 switch나 루프에서의 흐름 제어.
  • 리팩토링 대신 레이블을 사용하지 마세요: 로직이 복잡하면 별도 메서드로 추출하는 게 낫습니다.
  • 전형적인 사용 사례—switch가 포함된 foreach로 컬렉션 처리, 일부 case에서 외부 루프의 반복을 종료하거나 건너뛰는 경우.
  • 이 기능은 Open 상태이지만, 이미 C# 언어 그룹의 Working Set에 수용되었습니다.
  • 비교 불가능한 예시를 비교하지 마세요: 기존 코드와 새 코드는 동일한 작업을 해결해야 합니다.

— Editorial Team

Advertisement 728x90

다음 읽기