C# Pattern Matching 심층 가이드
패턴 매칭이란
섹션 제목: “패턴 매칭이란”패턴 매칭(Pattern Matching)은 값의 형태(shape) 를 검사해 분기하는 기법입니다. C# 7부터 단계적으로 확장되어 C# 11에서 리스트 패턴까지 지원합니다. 복잡한 if-else 체인과 캐스트 코드를 간결하고 안전하게 표현합니다.
타입 패턴 (Type Pattern)
섹션 제목: “타입 패턴 (Type Pattern)”// C# 7: is 타입 패턴object obj = "hello";
if (obj is string s){ Console.WriteLine(s.ToUpper()); // 타입 검사 + 선언 동시에}
// 부정: is notif (obj is not int){ Console.WriteLine("정수가 아님");}switch 표현식 (C# 8+)
섹션 제목: “switch 표현식 (C# 8+)”switch 문을 표현식으로 사용해 값을 반환합니다.
// 전통적 switch 문string GetDayType(DayOfWeek day){ switch (day) { case DayOfWeek.Saturday: case DayOfWeek.Sunday: return "주말"; default: return "평일"; }}
// switch 표현식 (C# 8+)string GetDayType(DayOfWeek day) => day switch{ DayOfWeek.Saturday or DayOfWeek.Sunday => "주말", _ => "평일"};타입 switch 표현식
섹션 제목: “타입 switch 표현식”abstract class Shape { }class Circle : Shape { public double Radius; }class Rectangle : Shape { public double W, H; }class Triangle : Shape { public double Base, Height; }
double GetArea(Shape shape) => shape switch{ Circle c => Math.PI * c.Radius * c.Radius, Rectangle r => r.W * r.H, Triangle t => 0.5 * t.Base * t.Height, null => throw new ArgumentNullException(nameof(shape)), _ => throw new NotSupportedException($"Unknown shape: {shape.GetType()}")};속성 패턴 (Property Pattern, C# 8+)
섹션 제목: “속성 패턴 (Property Pattern, C# 8+)”객체의 속성값을 패턴으로 매칭합니다.
record Point(int X, int Y);
string ClassifyPoint(Point p) => p switch{ { X: 0, Y: 0 } => "원점", { X: 0 } => "Y축 위", { Y: 0 } => "X축 위", { X: > 0, Y: > 0 } => "1사분면", { X: < 0, Y: > 0 } => "2사분면", { X: < 0, Y: < 0 } => "3사분면", _ => "4사분면"};
Console.WriteLine(ClassifyPoint(new Point(3, 4))); // 1사분면중첩 속성 패턴
섹션 제목: “중첩 속성 패턴”record Address(string City, string Country);record Person(string Name, Address Address);
string GetRegion(Person person) => person switch{ { Address: { Country: "KR", City: "Seoul" } } => "서울", { Address: { Country: "KR" } } => "한국 (서울 외)", { Address: { Country: "US" } } => "미국", _ => "기타"};위치 패턴 (Positional Pattern, C# 8+)
섹션 제목: “위치 패턴 (Positional Pattern, C# 8+)”Deconstruct 메서드가 있는 타입을 분해해 매칭합니다.
record Point(int X, int Y){ public void Deconstruct(out int x, out int y) => (x, y) = (X, Y);}
string Quadrant(Point p) => p switch{ (0, 0) => "원점", (> 0, > 0) => "1사분면", (< 0, > 0) => "2사분면", (< 0, < 0) => "3사분면", (> 0, < 0) => "4사분면", (0, _) => "Y축", (_, 0) => "X축", _ => "알 수 없음"};관계 패턴 (Relational Pattern, C# 9+)
섹션 제목: “관계 패턴 (Relational Pattern, C# 9+)”비교 연산자를 패턴으로 사용합니다.
string GetGrade(int score) => score switch{ >= 90 => "A", >= 80 => "B", >= 70 => "C", >= 60 => "D", _ => "F"};
// 논리 패턴: and, or, notbool IsValidTemperature(double temp) => temp is >= -273.15 and <= 1000.0;
bool IsWeekend(DayOfWeek day) => day is DayOfWeek.Saturday or DayOfWeek.Sunday;리스트 패턴 (List Pattern, C# 11+)
섹션 제목: “리스트 패턴 (List Pattern, C# 11+)”배열이나 리스트의 구조를 패턴으로 매칭합니다.
int[] numbers = { 1, 2, 3, 4, 5 };
bool result = numbers switch{ [] => true, // 빈 배열 [1] => true, // 원소 1개, 값이 1 [1, 2, ..] => true, // 1로 시작하고 2가 두 번째 [.., 5] => true, // 마지막이 5 [1, .., 5] => true, // 1로 시작, 5로 끝 _ => false};
// 슬라이스 패턴으로 요소 캡처string Describe(int[] arr) => arr switch{ [] => "빈 배열", [var x] => $"원소 1개: {x}", [var h, .. var rest] => $"첫 번째: {h}, 나머지 {rest.Length}개"};when 가드 (Guard Clause)
섹션 제목: “when 가드 (Guard Clause)”패턴에 추가 조건을 붙입니다.
record Order(string Status, decimal Amount);
string ProcessOrder(Order order) => order switch{ { Status: "pending" } when order.Amount > 100_000 => "고액 결제 검토 필요", { Status: "pending" } => "결제 대기", { Status: "paid" } => "결제 완료", { Status: "cancelled" } => "취소됨", _ => $"알 수 없는 상태: {order.Status}"};var 패턴
섹션 제목: “var 패턴”항상 매칭되며 값을 캡처합니다.
// var 패턴은 항상 true, 값을 변수에 바인딩if (GetValue() is var result && result != null){ Console.WriteLine(result);}
// switch에서 공통 처리string Handle(object obj) => obj switch{ int n when n < 0 => $"음수: {n}", int n => $"양수: {n}", var x => $"기타: {x?.GetType().Name}"};실전 예제: JSON-like 파서
섹션 제목: “실전 예제: JSON-like 파서”abstract record JsonValue;record JsonNull : JsonValue;record JsonBool(bool Value) : JsonValue;record JsonNumber(double Value) : JsonValue;record JsonString(string Value) : JsonValue;record JsonArray(JsonValue[] Items) : JsonValue;
string Stringify(JsonValue value) => value switch{ JsonNull => "null", JsonBool { Value: true } => "true", JsonBool { Value: false } => "false", JsonNumber { Value: var n } => n.ToString("G"), JsonString { Value: var s } => $"\"{s}\"", JsonArray { Items: [] } => "[]", JsonArray { Items: var items } => $"[{string.Join(", ", items.Select(Stringify))}]", _ => throw new NotSupportedException()};| 패턴 | C# 버전 | 예시 |
|---|---|---|
| 타입 패턴 | 7.0 | obj is string s |
| switch 표현식 | 8.0 | x switch { ... } |
| 속성 패턴 | 8.0 | { X: 0, Y: 0 } |
| 위치 패턴 | 8.0 | (0, 0) |
| 관계 패턴 | 9.0 | >= 90 |
| 논리 패턴 | 9.0 | and, or, not |
| 리스트 패턴 | 11.0 | [1, .., 5] |
패턴 매칭은 가독성과 안전성을 동시에 높입니다. 특히 도메인 모델의 계층 구조를 처리할 때 상속 기반 다형성의 좋은 대안이 됩니다.