안녕하세요. 이번 글에서는 C#의 switch 식(switch expression)과 패턴 매칭(pattern matching)에 대해 알아보겠습니다.
기존 switch 문은 case마다 break를 쓰고 결과를 변수에 대입해야 해서 값을 고르는 용도로는 코드가 길어졌습니다. C# 8.0부터 값을 반환하는 switch 식이 추가되었고, 이후 버전에서 패턴이 계속 확장되어 조건 분기를 훨씬 간결하게 쓸 수 있습니다.
switch 문 vs switch 식
// before : switch 문
string name;
switch (day)
{
case 0: name = "Sun"; break;
case 6: name = "Sat"; break;
default: name = "Weekday"; break;
}
// after : switch 식 (C# 8.0)
string name2 = day switch
{
0 => "Sun",
6 => "Sat",
_ => "Weekday",
};
switch 식은 값 => 결과 형태로 쓰고, 나머지를 모두 받는 _ (discard)가 default 역할을 합니다. 어떤 입력도 처리하지 못하면 컴파일러가 경고하고, 실행 중에는 SwitchExpressionException이 발생합니다.
관계 패턴, 논리 패턴 (C# 9.0)
<, >, <=, >=로 범위를 비교하고, and, or, not으로 조합할 수 있습니다.
static string Grade(int score) => score switch
{
>= 90 => "A",
>= 80 => "B",
>= 70 => "C",
< 0 or > 100 => "Invalid",
_ => "F",
};
Console.WriteLine(Grade(85)); // B
Console.WriteLine(Grade(120)); // Invalid
위에서부터 차례로 검사하므로 순서가 중요합니다. 앞의 패턴이 뒤의 패턴을 모두 포함하면 컴파일 오류가 납니다.
형식 패턴과 속성 패턴
형식(type) 패턴은 객체의 실제 타입으로 분기하며, 속성 패턴은 { 속성: 값 } 형태로 속성 값을 검사합니다.
public record Circle(double Radius);
public record Rect(double Width, double Height);
static double Area(object shape) => shape switch
{
Circle c => Math.PI * c.Radius * c.Radius,
Rect { Width: var w, Height: var h } => w * h,
null => 0,
_ => throw new ArgumentException("알 수 없는 도형"),
};
속성 패턴은 값을 추출하지 않고 조건만 검사할 수도 있습니다.
static string Check(Rect r) => r switch
{
{ Width: 0 } or { Height: 0 } => "Empty",
{ Width: var w, Height: var h } when w == h => "Square",
_ => "Rectangle",
};
튜플 패턴
두 값 이상을 묶어 한 번에 비교할 때는 튜플 패턴이 편리합니다.
static string Rps(string a, string b) => (a, b) switch
{
("rock", "scissors") or ("scissors", "paper") or ("paper", "rock") => "A win",
("rock", "paper") or ("scissors", "rock") or ("paper", "scissors") => "B win",
_ => "Draw",
};
is 식과 패턴
switch가 아니더라도 is 식에서 같은 패턴을 쓸 수 있습니다. 타입 검사와 변환을 한 번에 하고, not 패턴으로 null 검사도 간결해집니다.
if (obj is string s && s.Length > 0)
Console.WriteLine(s.ToUpper());
if (obj is not null)
Console.WriteLine("값이 있습니다.");
if (age is >= 7 and <= 19)
Console.WriteLine("학생 연령");
주의할 점
- switch 식의 각 갈래는 결과 타입이 공통 타입으로 맞아야 합니다.
- 패턴은 위에서 아래로 평가되므로, 범위가 넓은 패턴을 먼저 두면 뒤의 패턴이 도달 불가능해져 컴파일 오류가 납니다.
- _ 갈래가 없으면 처리하지 못하는 값에서 예외가 발생할 수 있으니 열거형을 제외하면 _ 를 두는 편이 안전합니다.
- 복잡한 조건을 한 식에 모두 넣으면 오히려 읽기 어려워지므로 갈래가 길어지면 메서드로 분리합니다.
정리
switch 식은 값을 고르는 분기를 한 식으로 표현하고, 관계·논리·속성·튜플 패턴은 조건을 선언적으로 적게 해 줍니다. 단순 값 매핑부터 객체의 타입과 상태에 따른 분기까지 같은 문법으로 다룰 수 있어서 if-else 사슬을 대체하기 좋습니다.
이상으로 switch 식과 패턴 매칭에 대해 간단히 알아보았습니다.