switch 문은 하나의 값을 상수 case 레이블 목록과 비교하고 일치하는 섹션을 실행합니다. C#에서는 모든 섹션이 break(또는 섹션을 빠져나가는 다른 문장)로 끝나야 하므로, 한 case가 조용히 다음 case로 이어지는 일이 절대 없습니다.
출력:
200: OK
302: redirect
404: not found
500: unhandled status
괄호 안의 값은 한 번 평가되어 각 레이블과 비교됩니다. default는 아무것도 일치하지 않을 때 실행되며, 선택 사항이고 목록 어디에나 둘 수 있지만 보통 마지막에 둡니다. 일치하는 것도 default도 없으면 switch 전체가 아무 일도 하지 않습니다.
모든 섹션에는 break가 필요합니다
C, C++, Java, JavaScript에서는 break를 잊으면 실행이 다음 case로 미끄러져 들어갑니다. C#은 이 실수를 컴파일 오류로 만듭니다:
switch (level)
{
case 1:
Console.WriteLine("read");
// error CS0163: Control cannot fall through from one case label ('case 1:') to another
case 2:
Console.WriteLine("write");
break;
}
규칙은 섹션의 문장 목록 끝에 도달할 수 없어야 한다는 것입니다. 보통은 break로 이를 만족시키지만, 섹션을 빠져나가는 것이면 무엇이든 됩니다:
return은 메서드 전체를 빠져나가며, 작은 헬퍼 안에서는 가장 깔끔한 형태인 경우가 많습니다.throw는 절대 나오면 안 되는 값에 대해 예외를 발생시킵니다.continue는switch가 루프 안에 있을 때 다음 반복으로 건너뜁니다.goto case와goto default는 의도적으로 다른 섹션으로 점프합니다.
마지막 섹션도 예외가 아닙니다. 맨 아래의 default:에 break가 없으면 CS8070 Control cannot fall out of switch from final case label ('default:')로 실패합니다.
한 case에 여러 값
사이에 문장이 없는 레이블들은 그 아래 섹션을 공유합니다. 빈 레이블은 어떤 코드도 숨길 수 없으므로, C#이 허용하는 유일한 종류의 fall through입니다:
출력:
'O' is a vowel
'k' is a consonant or symbol
' ' is a space
'7' is a digit
여기서는 각 섹션이 return으로 끝나므로 break가 필요 없습니다(return 뒤의 break는 도달할 수 없는 코드가 됩니다). 같은 값을 가진 두 레이블은 오류 CS0152 The switch statement contains multiple cases with the label value '1'이며, 모든 레이블은 컴파일 시점 상수여야 합니다. case에 변수를 쓰면 "a constant value is expected"로 실패합니다.
문자열로 switch하기
정수 다음으로 가장 흔한 switch 값은 문자열입니다. 비교는 대소문자를 구분하는 서수 비교이므로, switch하기 전에 입력을 정규화하세요:
출력:
Starting the server
Stopping the server
Server is running
Unknown command: restart
Unknown command: (none)
ToLowerInvariant가 없다면 "STOP"은 default로 갑니다. null 값으로 switch하는 것은 허용됩니다. 어떤 문자열 상수에도 걸리지 않고 default로 떨어지므로 switch 자체는 예외를 던지지 않습니다.
열거형으로 switch하기
열거형은 switch가 만들어진 이유입니다. 이름 붙은 값의 닫힌 집합이기 때문입니다.
출력:
Pending: wait for payment
Paid: pack and ship
Shipped: track the parcel
Delivered: nothing, order is closed
Cancelled: nothing, order is closed
ArgumentOutOfRangeException for value 42
컴파일러는 switch 문이 열거형의 모든 멤버를 다루는지 검사하지 않으며, 열거형 변수는 기반 타입의 어떤 정수든 담을 수 있습니다((OrderStatus)42도 허용됩니다). 예외를 던지는 default는 빠뜨린 case를 조용히 아무것도 안 하는 대신 즉각적이고 분명한 실패로 바꿔 줍니다.
goto case와 goto default
한 case가 정말로 다른 case로 이어져야 할 때, C#은 점프를 직접 쓰게 합니다:
출력:
admin:
manage users
edit posts
read posts
editor:
edit posts
read posts
guest:
read posts
goto case는 같은 switch의 레이블 중 하나와 일치하는 상수를 받습니다. 실제 코드에서는 드뭅니다. 공유 동작은 보통 여러 case가 호출하는 메서드로 만드는 편이 더 명확합니다. 그래도 "C#에서 fall through는 어떻게 하나요?"에 대한 답은 이것입니다.
case 안의 변수
switch 블록 전체가 하나의 범위이므로 두 case에서 같은 이름의 변수를 선언할 수 없습니다:
switch (shape)
{
case "square":
int area = side * side;
break;
case "rectangle":
int area = width * height; // error CS0128: A local variable or function named 'area' is already defined in this scope
break;
}
각 섹션 본문을 중괄호로 감싸면 섹션마다 자기 범위가 생깁니다: case "square": { int area = side * side; ... break; }.
루프 안의 break
case 안의 break는 둘러싼 루프가 아니라 switch를 빠져나갑니다. continue는 반대입니다. switch는 루프가 아니므로 continue는 루프의 다음 반복으로 갑니다.
출력:
end marker found
Total: 134
루프는 "end" 뒤에도 계속 돌아서 99를 더했습니다. switch 안에서 루프를 멈추려면 플래그를 설정하고 switch 뒤에서 검사하거나, 루프를 메서드로 옮기고 return하세요. break와 continue 페이지에서 선택지를 비교합니다.
패턴 case 레이블과 when
C# 7.0부터는 case 레이블이 상수 대신 패턴이 될 수 있습니다. 값의 타입을 검사하고 when 조건을 덧붙일 수 있습니다. 최신 C# 코드에서 흔한 형태입니다:
static string Describe(object value)
{
switch (value)
{
case null:
return "nothing";
case int n when n < 0:
return $"negative int {n}";
case int n:
return $"int {n}";
case string s when s.Length == 0:
return "empty string";
case string s:
return $"string \"{s}\"";
default:
return $"other: {value.GetType().Name}";
}
}
패턴에서는 순서가 중요합니다. 처음 일치하는 case가 이기며, 앞의 case가 이미 모두 덮어서 도달할 수 없는 case가 있으면 컴파일러가 오류를 보고합니다(case int n when n < 0: 위에 case int n:을 두면 실패합니다). when 절은 상수 case에도 쓸 수 있습니다: case 0 when isAdmin:. C# 9는 관계 패턴과 논리 패턴을 추가해서 case를 case >= 90:이나 case 'a' or 'e' or 'i':로 쓸 수 있습니다.
패턴이 없는 C# 7에서는 같은 타입 분기를 is 타입 패턴을 쓴 if 체인으로 씁니다:
출력:
negative int -3
int 12
empty string
string "hi"
other: Decimal
nothing
switch의 모든 분기가 값만 계산한다면 switch 식이 더 짧습니다: var grade = score switch { >= 90 => "A", >= 80 => "B", _ => "C" };. switch 식 페이지에서 문법, 패턴, 완전성 규칙을 다룹니다.
switch할 수 있는 값
| 값 타입 | 상수 case | 참고 |
|---|---|---|
int, long, byte와 그 밖의 정수 | 가능 | 전형적인 경우 |
char | 가능 | case 'a': |
string | 가능 | 서수, 대소문자 구분, null은 default로 |
bool | 가능 | 허용되지만 if가 더 명확 |
모든 enum | 가능 | 완전성 검사 없음 |
double, decimal | C# 7부터 | 상수만, 범위에는 C# 9 관계 패턴 필요 |
| 그 밖의 모든 타입 | C# 7부터 | 타입 패턴으로, case Circle c: |
자주 묻는 질문
C# switch에서 break는 꼭 필요한가요?
모든 case 섹션은 섹션을 빠져나가는 문장으로 끝나야 합니다. 보통 break이지만 return, throw, (루프 안의) continue, goto case도 됩니다. 섹션 끝에서 다음 섹션으로 흘러 들어가는 것은 컴파일 오류 CS0163 Control cannot fall through from one case label ('case 1:') to another이며, 마지막 섹션도 마찬가지입니다.
C# switch의 한 case에서 여러 값을 처리하려면 어떻게 하나요?
레이블 사이에 아무것도 두지 않고 겹쳐 씁니다: case "sat": case "sun": Console.WriteLine("weekend"); break;. 빈 case 레이블은 다음 레이블로 흘러갈 수 있고, 문장이 들어 있는 섹션만 break로 끝나야 합니다. C# 9 이상에서는 패턴 case로 case 1 or 2 or 3:이라고 쓸 수도 있습니다.
C#에서 문자열 switch는 대소문자를 구분하나요?
네. 문자열 case는 대소문자를 구분하는 서수 비교로 비교하므로 "Yes"는 case "yes":에 걸리지 않습니다. 먼저 switch (input.Trim().ToLowerInvariant())로 값을 정규화하세요. null 문자열은 어떤 상수 case에도 걸리지 않고 default로 갑니다.
C# switch도 C나 Java처럼 fall through할 수 있나요?
암묵적으로는 안 됩니다. 한 case가 다른 case로 이어지게 하려면 goto case <value>;나 goto default;로 명시하세요. 이렇게 하면 모든 fall through가 코드에 드러나며, 그래서 C#은 조용한 fall through를 금지합니다.
C#에서 switch 문과 switch 식의 차이는 무엇인가요?
switch 문은 문장을 실행하며 case, break, default가 필요합니다. switch 식(C# 8 이상)은 값을 만듭니다: var label = n switch { 0 => "zero", > 0 => "positive", _ => "negative" };. 모든 분기가 결과만 계산한다면 식을 쓰세요.