서론
안녕하세요, 컴퓨터 공학을 전공하고 게임 개발에 관심 있는 취업 준비생입니다. 오늘은 '이것이 C#이다' 책의 5장 내용을 정리하며, C#에서 코드의 흐름을 제어하는 방법에 대해 깊이 있게 살펴보겠습니다. 특히 switch 문, 점프문, 그리고 C#의 강력한 기능인 패턴 매칭에 초점을 맞춰 설명하겠습니다.
본론
1. 조건문: switch 문과 패턴 매칭
C#의 switch 문은 단순히 값을 비교하는 것을 넘어서 강력한 패턴 매칭 기능을 제공합니다. 이는 코드의 가독성을 높이고 복잡한 조건 로직을 간결하게 표현할 수 있게 해줍니다.
1.1 케이스 가드
케이스 가드(case guard)는 switch 문의 case 절에 추가적인 조건을 부여하는 기능입니다. when 키워드를 사용하여 구현합니다.
switch (obj)
{
case int i:
Console.WriteLine($"It's an integer: {i}");
break;
case float f when f >= 0:
Console.WriteLine($"It's a non-negative float: {f}");
break;
case float f:
Console.WriteLine($"It's a negative float: {f}");
break;
default:
Console.WriteLine("It's neither an integer nor a float");
break;
}
C#
복사
이 예제에서 float 타입의 경우, 양수와 음수를 구분하여 처리하고 있습니다. 이러한 방식은 복잡한 조건문을 보다 구조화된 형태로 표현할 수 있게 해줍니다.
1.2 switch 식
C# 8.0부터는 switch 식(expression)을 사용할 수 있습니다. 이는 기존의 switch 문을 더욱 간결하게 만들어줍니다.
string GetGrade(int score, bool repeated) => score switch
{
90 when repeated == true => "B+",
90 => "A",
80 => "B",
70 => "C",
60 => "D",
_ => "F"
};
C#
복사
switch 식은 함수형 프로그래밍 스타일을 선호하는 개발자들에게 특히 유용합니다. 코드가 더 간결해지고, 가독성이 향상되며, 실수할 가능성도 줄어듭니다.
2. 점프문: goto의 재발견
C#은 break, continue, return, throw와 같은 일반적인 점프문 외에도 goto 문을 제공합니다. goto는 흔히 안티패턴으로 여겨지지만, 특정 상황에서는 유용할 수 있습니다.
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 3; k++)
{
if (someCondition)
goto EXIT_NESTED_LOOPS;
Console.WriteLine($"i:{i}, j:{j}, k:{k}");
}
}
}
EXIT_NESTED_LOOPS:
Console.WriteLine("Exited nested loops");
C#
복사
이 예제에서 goto는 깊게 중첩된 루프를 한 번에 빠져나오는 데 사용됩니다. 하지만 goto의 과도한 사용은 코드의 흐름을 복잡하게 만들 수 있으므로 주의가 필요합니다. 대부분의 경우 함수 추출이나 다른 제어 구조를 사용하는 것이 더 좋은 방법입니다.
3. 패턴 매칭: C#의 강력한 기능
패턴 매칭은 C# 7.0부터 도입된 강력한 기능으로, 복잡한 데이터 구조를 효과적으로 분석하고 처리할 수 있게 해줍니다. 이는 함수형 프로그래밍 언어에서 영감을 받아 설계되었으며, 객체 지향 패러다임과 함수형 프로그래밍 스타일을 융합한 좋은 예시입니다.
패턴 매칭을 사용하면 코드의 가독성이 향상되고, 복잡한 조건문을 더 간결하고 명확하게 표현할 수 있습니다. 또한, 컴파일러가 패턴 매칭의 완전성을 검사하므로 런타임 오류를 줄일 수 있습니다.
이제 C#에서 제공하는 다양한 패턴 유형에 대해 자세히 살펴보겠습니다.
3.1 선언 패턴 (Declaration Pattern)
선언 패턴은 입력 데이터의 타입을 검사하고, 해당 타입으로 캐스팅까지 동시에 수행합니다.
object obj = "Hello, World!";
if (obj is string str)
{
Console.WriteLine($"String length: {str.Length}");
}
C#
복사
이 패턴은 타입 검사와 캐스팅을 한 번에 처리하여 코드를 간결하게 만듭니다.
3.2 형식 패턴 (Type Pattern)
형식 패턴은 C# 9.0에서 도입되었으며, 선언 패턴과 유사하지만 변수 선언 없이 타입만 확인합니다.
object obj = 42;
if (obj is int)
{
Console.WriteLine("It's an integer");
}
C#
복사
3.3 상수 패턴 (Constant Pattern)
상수 패턴은 입력 값이 특정 상수와 일치하는지 검사합니다.
object obj = 3.14;
if (obj is 3.14)
{
Console.WriteLine("It's pi!");
}
C#
복사
3.4 관계 패턴 (Relational Pattern)
관계 패턴은 C# 9.0에서 도입되었으며, 숫자형 데이터의 대소 관계를 비교합니다.
static string GetTemperature(double celsius) => celsius switch
{
> 30 => "Hot",
> 20 => "Warm",
> 10 => "Cool",
_ => "Cold"
};
C#
복사
3.5 논리 패턴 (Logical Pattern)
논리 패턴은 여러 패턴을 and, or, not 연산자로 결합합니다.
static string ClassifyNumber(int n) => n switch
{
< 0 and > -10 => "Small negative",
< 0 => "Negative",
0 => "Zero",
> 0 and < 10 => "Small positive",
> 0 => "Positive",
};
C#
복사
3.6 프로퍼티 패턴 (Property Pattern)
프로퍼티 패턴은 객체의 속성을 검사합니다.
class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
}
static string ClassifyProduct(Product p) => p switch
{
{ Name: "Apple", Price: < 1.0m } => "Cheap apple",
{ Name: "Apple", Price: >= 1.0m } => "Expensive apple",
{ Name: "Orange" } => "Orange",
_ => "Unknown product"
};
C#
복사
3.7 위치 패턴 (Positional Pattern)
위치 패턴은 튜플이나 분해 가능한 타입의 요소를 패턴 매칭합니다.
static string Classify(object obj) => obj switch
{
(1, string id) => $"ID: {id}",
(2, int age, string name) => $"Name: {name}, Age: {age}",
(3, _, _) => "Three elements, first is 3",
_ => "Unknown pattern"
};
C#
복사
3.8 var 패턴 (var Pattern)
var 패턴은 모든 입력과 매칭되며, 해당 값을 변수에 할당합니다.
static void ProcessValue(object obj)
{
if (obj is var x)
{
Console.WriteLine($"Type: {x.GetType()}, Value: {x}");
}
}
C#
복사
3.9 무시 패턴 (Discard Pattern)
무시 패턴은 언더스코어(_)를 사용하여 특정 값을 무시합니다.
static string GetFirstElement(object obj) => obj switch
{
(var first, _) => $"First: {first}",
_ => "Not a tuple"
};
C#
복사
3.10 목록 패턴 (List Pattern)
C# 11에서 도입된 목록 패턴은 배열이나 리스트의 요소를 패턴 매칭합니다.
static string AnalyzeList(int[] numbers) => numbers switch
{
[1, 2, ..] => "Starts with 1, 2",
[.., 3, 4] => "Ends with 3, 4",
[1, .., 4] => "Starts with 1, ends with 4",
[] => "Empty list",
_ => "Does not match any pattern"
};
C#
복사
3.11 패턴 매칭의 이점 및 주의점
패턴 매칭의 주요 이점은 다음과 같습니다:
1.
코드 가독성 향상
2.
복잡한 조건문의 간결한 표현
3.
컴파일 시점에서의 패턴 완전성 검사
4.
데이터 구조의 분해와 분석 용이성
하지만 과도한 사용은 오히려 코드를 복잡하게 만들 수 있으므로 적절한 사용이 중요합니다. 또한, 성능에 민감한 상황에서는 패턴 매칭의 오버헤드를 고려해야 합니다.
결론
C#의 흐름 제어 구문, 특히 패턴 매칭은 코드의 가독성과 유지보수성을 크게 향상시킵니다. switch 식과 다양한 패턴을 활용하면, 복잡한 로직을 더 간결하고 명확하게 표현할 수 있습니다.
이번 학습을 통해 C#의 현대적인 기능들이 얼마나 강력한지 다시 한 번 깨달았습니다. 특히 패턴 매칭은 함수형 프로그래밍의 장점을 객체 지향 언어에 도입한 훌륭한 예시라고 생각합니다.
참고 자료
•
박상현, "이것이 C#이다", 한빛미디어, 2023