---
title: "switch 는 조건이 아니라 값을 본다"
description: "else if 사슬이 같은 변수를 계속 다시 묻고 있다면 switch 자리입니다. 범위는 if, 목록은 switch입니다."
author: "유니얼"
pubDate: 2026-09-08
category: "programming/csharp/basics"
tags: ["C#", "기초"]
canonical: https://blog.unialgames.com/posts/csharp-switch/
---
앞 글의 `else if` 사슬로 요일을 찍어 보겠습니다.

```csharp
if (day == 1)
{
    Console.WriteLine("월요일");
}
else if (day == 2)
{
    Console.WriteLine("화요일");
}
else if (day == 3)
{
    Console.WriteLine("수요일");
}
```

일곱 개까지 이어집니다. 그런데 자세히 보면 조건이 전부 같은 모양입니다.
변수도 `day` 하나, 연산자도 `==` 하나. 바뀌는 것은 오른쪽 값뿐입니다.

> **묻는 것이 "이 값이 무엇인가" 하나뿐일 때 쓰는 문법이 `switch` 입니다.**

## switch 는 이렇게 생겼다

<figure class="diagram">
<svg viewBox="0 0 680 290" role="img" aria-label="switch 문의 생김새. 맞춰 볼 값, case 후보, break, default 로 나뉜 그림">
<g font-family="var(--font-mono)" font-size="15">
<text x="40" y="34" fill="var(--accent)">switch</text>
<text x="106" y="34" fill="var(--text)">(값)</text>
<text x="40" y="62" fill="var(--text-muted)">{</text>
<text x="72" y="90" fill="var(--accent)">case</text>
<text x="118" y="90" fill="var(--text)">후보:</text>
<text x="104" y="118" fill="var(--text-muted)">실행할 코드</text>
<text x="104" y="146" fill="var(--accent)">break;</text>
<text x="72" y="174" fill="var(--accent)">default:</text>
<text x="104" y="202" fill="var(--text-muted)">실행할 코드</text>
<text x="104" y="230" fill="var(--accent)">break;</text>
<text x="40" y="258" fill="var(--text-muted)">}</text>
</g>
<g stroke="var(--border)" stroke-width="1.4" fill="none">
<path d="M160 30 L320 30"></path>
<path d="M175 86 L320 86"></path>
<path d="M170 142 L320 142"></path>
<path d="M160 170 L320 170"></path>
</g>
<g font-size="13" fill="var(--text-muted)">
<text x="332" y="34">맞춰 볼 값 하나</text>
<text x="332" y="90">값이 이것과 같으면 여기로 뛴다</text>
<text x="332" y="146">여기서 switch 를 빠져나온다</text>
<text x="332" y="174">맞는 후보가 하나도 없을 때</text>
</g>
</svg>
<figcaption>맞춰 볼 값 하나, 후보 목록, 그리고 나가는 문.</figcaption>
</figure>

`if` 는 괄호 안에 **조건**이 들어갔습니다. `switch` 는 괄호 안에 **값**이 들어갑니다.
`day > 3` 같은 것을 넣을 수 없습니다. 참거짓을 묻는 자리가 아니라
"이 값이 무엇이냐"를 묻는 자리이기 때문입니다.

## 맞는 자리로 바로 뛴다

<x-flow>
<script type="application/json">
{
  "label": "값 하나를 후보와 맞춘다",
  "lines": [
    "switch (day)",
    "{",
    "    case 1:",
    "        Console.WriteLine(\"월요일\");",
    "        break;",
    "    case 4:",
    "        Console.WriteLine(\"목요일\");",
    "        break;",
    "    default:",
    "        Console.WriteLine(\"그런 요일은 없습니다\");",
    "        break;",
    "}",
    "Console.WriteLine(\"여기로 이어집니다\");"
  ],
  "cases": [
    {
      "label": "day = 4",
      "state": "day = 4",
      "path": [
        { "line": 0, "why": "괄호 안의 값을 꺼냅니다. 조건이 아니라 값입니다.", "verdict": "4" },
        { "line": 5, "why": "후보를 위에서부터 훑는 것이 아니라 맞는 자리로 바로 갑니다." },
        { "line": 6, "why": "그 case 아래가 실행됩니다.", "out": "목요일" },
        { "line": 7, "why": "break 를 만나면 switch 밖으로 나갑니다." },
        { "line": 12, "why": "어느 case 로 갔든 여기서 다시 만납니다.", "out": "여기로 이어집니다" }
      ],
      "skip": [2, 3, 4, 8, 9, 10],
      "note": "흐린 줄은 이번에 지나가지 않은 case 입니다."
    },
    {
      "label": "day = 9",
      "state": "day = 9",
      "path": [
        { "line": 0, "why": "이번에는 후보에 없는 값입니다.", "verdict": "9" },
        { "line": 8, "why": "맞는 case 가 하나도 없으면 default 로 갑니다." },
        { "line": 9, "why": "default 아래가 실행됩니다.", "out": "그런 요일은 없습니다" },
        { "line": 10, "why": "여기도 break 로 닫습니다." },
        { "line": 12, "why": "그리고 다시 한 줄로 이어집니다.", "out": "여기로 이어집니다" }
      ],
      "skip": [2, 3, 4, 5, 6, 7],
      "note": "default 가 없으면 이 경우에 switch 는 아무 일도 하지 않고 지나갑니다."
    }
  ]
}
</script>
</x-flow>

`else if` 사슬은 위에서부터 조건을 하나씩 검사했습니다.
`switch` 는 그럴 필요가 없습니다. 물어보는 것이 "같은 값인가" 하나뿐이라
컴파일러가 후보를 미리 정리해 둘 수 있기 때문입니다.
후보가 몇 개 안 되면 그냥 비교하지만, 많아지면 표를 만들어 두고 곧장 그 자리로 보냅니다.

**후보가 늘어나도 찾는 비용이 그만큼 늘지 않는다는 것**이 `switch` 의 성질입니다.
`else if` 는 마지막 후보에 걸리려면 앞의 조건을 전부 지나가야 합니다.

## break 는 선택이 아니다

C# 은 `case` 아래 코드가 있으면 반드시 `break` 같은 것으로 닫아야 합니다.
안 닫으면 컴파일이 안 됩니다.

```csharp
switch (day)
{
    case 1:
        Console.WriteLine("월요일");
        // break 가 없으면 컴파일 에러
    case 2:
        Console.WriteLine("화요일");
        break;
}
```

C나 Java에서는 이게 그냥 통과합니다. 그리고 `break` 를 빠뜨리면
아래 `case` 로 그대로 흘러내려서 월요일과 화요일이 같이 찍힙니다.
찾기 어려운 종류의 버그였고, C# 은 이걸 문법으로 막았습니다.

여러 값을 같은 코드로 처리하고 싶을 때는 `case` 를 붙여서 씁니다.
이건 사이에 코드가 없으니 허용됩니다.

```csharp
switch (day)
{
    case 6:
    case 7:
        Console.WriteLine("주말");
        break;
    default:
        Console.WriteLine("평일");
        break;
}
```

## default 는 else 다

`default` 는 `else` 와 같은 자리입니다. 어느 후보에도 안 걸린 값이 전부 여기로 옵니다.

`else` 와 마찬가지로 필수가 아닙니다. 안 쓰면 맞는 `case` 가 없을 때
`switch` 는 아무 일도 하지 않고 지나갑니다. 에러도 경고도 없습니다.

**후보를 다 적었다고 생각할 때가 위험합니다.** 요일이 1부터 7이니 `case` 를 일곱 개 적으면
끝이라고 생각하지만, `day` 에 0이나 100이 들어올 수 있다면 그때는 조용히 아무 일도 안 일어납니다.
`default` 는 "그럴 리 없다"를 눈에 보이게 적어두는 자리입니다.

## 범위는 if, 목록은 switch

둘 중 무엇을 쓸지는 조건의 모양이 정합니다.

| | if / else if | switch |
| --- | --- | --- |
| 조건 형태 | 어떤 조건식이든 | 하나의 값과 같은지만 |
| 범위 비교 | `age >= 19` 가능 | 불가능 |
| 복합 조건 | `&&`, `\|\|` 조합 가능 | 불가능 |
| 후보가 많을 때 | 길어지고 읽기 어렵다 | 한눈에 보인다 |
| 대표 예 | 가격, 등급, 자격 판정 | 요일, 메뉴 번호, 상태 값 |

앞 글의 등급 코드는 `switch` 로 못 바꿉니다. `score >= 90` 은 값이 아니라 범위니까요.
반대로 요일 출력은 `else if` 로 쓸 수는 있지만, 같은 질문을 일곱 번 반복해서 적게 됩니다.

**고를 수 있는 후보가 정해져 있으면 `switch`, 재야 하면 `if`** 입니다.

`switch` 괄호에 넣을 수 있는 것은 값이 딱 떨어지는 타입입니다.
정수, `char`, `string`, `bool`, 그리고 뒤에 나올 `enum`.
`double` 처럼 같은지를 따지기 어려운 타입은 여기 어울리지 않습니다.
앞에서 본 대로 `0.1 + 0.2 == 0.3` 이 거짓인 타입으로 후보를 맞출 수는 없습니다.

## 정리

- 묻는 것이 "이 값이 무엇인가" 하나뿐일 때 쓰는 문법이 `switch` 입니다.
- `if` 괄호에는 조건이, `switch` 괄호에는 값이 들어갑니다. 범위 비교는 못 씁니다.
- 맞는 `case` 로 곧장 갑니다. 후보가 늘어도 찾는 비용이 그만큼 늘지 않습니다.
- `case` 아래 코드가 있으면 `break` 로 닫아야 합니다. 안 닫으면 컴파일 에러입니다.
- 값 여러 개를 같이 처리하려면 `case` 를 사이에 코드 없이 붙여 씁니다.
- `default` 는 `else` 자리입니다. 없으면 아무 일도 안 하고 지나갑니다.