[C#] C#에서 사용하는 Switch case
개요
Switch case란?
=> Switch case는 다들 많이 사용하시기에 익숙하실 겁니다.
역할은 간단하게 주어진 식에 따라 분기를 나누는 역할을합니다.
다만 오늘 알아볼 건 기본적인 Switch case보다 조금 응용을 한 Switch case를 한번 알아볼까 합니다.
예제
기본형
먼저 C, C#, C++등 어디에도 아래와 같은 형식은 공통 부분입니다.
int _flag = 2;
switch(_flag)
{
case 1:
Function1();
break;
case 2:
Function2();
break;
default:
Function3();
break;
}
약간 다른점이 있다면 C#에서는 C & C++에서 가능한 묵시적인 Fall-through가 안된다는 부분입니다. (C#에서 Fall-through을 사용하려면 아래와 같이 goto를 사용해야 됩니다.)
int flag = 3;
switch (flag)
{
case 1:
DoFunc1();
goto case 2;
case 2:
DoFunc2();
goto default;
default:
DoFunc3();
break;
}
여기서 잠깐, Fall-through란?
Switch case에서 주의점 중 하나는 switch 표현식의 값과 일치 할 때 실행이 진행되는 방식 입니다.
이때 값이 일치하는 case 레이블을 만나거나 default case문이 실행되면 해당 레이블 다음의 첫번째 명령문이 실행되고 다음의 조건중 하나를 충족 될 때까지 실행이 계속 됩니다.
- switch 블록의 끝에 도달할 경우
- return 문이 발생할 경우
- goto 문이 발생할 경우
- break 문이 발생할 경우
- 호출, 예외 등 프로그램의 정상적인 흐름이 방해된 경우
상기의 조건중 하나가 충족 되지 않으면 case문은 계속 후속 case문으로 넘어갑니다.
이때 실행 흐름이 한 case에서 다른 case로 넘어가는 경우를 Fall-through라고 하는데,
Fall-through이 의도적인 경우는 거의 없으므로 반드시 주의 해야 합니다.
switch (2)
{
case 1: // Not match
std::cout << 1 << '\n'; // skipped
case 2: // Match!
std::cout << 2 << '\n'; // Execution begins here
case 3:
std::cout << 3 << '\n'; // This is also executed
case 4:
std::cout << 4 << '\n'; // This is also executed
default:
std::cout << 5 << '\n'; // This is also executed
}
기본적인 switch case의 사용법은 여기까지이며, 아래에서 부터는 응용된 switch case문을 알아 보도록 하겠습니다.
응용
C# 7.0에서 switch case문에서 패턴 패칭 식을 사용 가능 합니다.
원래 상기의 기본형 처럼 switch의 조건식에는 값 형식의 식들만 들어갈 수 있었지만, 이제는 그런 제한이 사라졌습니다.
클래스의 인스턴스도 들어갈 수 있으며, case문에는 패턴 매칭 식을 넣을 수가 있습니다.
using System;
public class Program
{
public static void Main()
{
// object data = "Test";
// object data = 3.14;
// object data = DateTime.Now;
object data = 13;
switch (data)
{
case "Test":
Console.WriteLine($"data is string: {data}");
break;
case 3.14:
Console.WriteLine($"data is double: {data}");
break;
case DateTime:
Console.WriteLine($"data is DateTime: {data}");
break;
case 13:
Console.WriteLine($"data is int: {data}");
break;
default:
Console.WriteLine("No Match");
break;
}
}
}
상기의 DateTime에서 보실 수 있듯이, 이제는 case가 상수식만 받지 않고 타입도 받을 수 있습니다.
따라서 아래와 같이 작성해도 동일하게 작동합니다.
case int:
case string:
case double:
case DateTime:
참고로, 각각에 해당하는 변수가 피룡할 경우 바로 변수명을 정의 하여 사용할 수도 있습니다.
case int i:
case string s:
case double f:
case DateTime dt:
변수명을 정의하여 바로 사용할 경우 아래와 같이 when을 사용하여 나타낼 수도 있습니다.
using System;
public class Program
{
public static void Main()
{
object data = 5;
switch (data)
{
case int i when i > 10: // data가 int 타입이고 10보다 큰 경우
Console.WriteLine($"data is int: {data} > 10");
break;
case int i when i <= 10: // data가 int 타입이고 10 이하인 경우
Console.WriteLine($"data is int: {data} <= 10");
break;
}
}
}
다음은 C#8.0의 Switch expression입니다.
예시로 요일을 string으로 반환 하는 식은 다음과 같습니다.
using System;
public class Program
{
public static void Main()
{
Console.WriteLine(GetDay());
}
public static string GetDay()
{
switch (DateTime.Now.DayOfWeek)
{
case DayOfWeek.Monday:
return "Monday";
case DayOfWeek.Tuesday:
return "Tuesday";
case DayOfWeek.Wednesday:
return "Wednesday";
case DayOfWeek.Thursday:
return "Thursday";
case DayOfWeek.Friday:
return "Friday";
case DayOfWeek.Saturday:
return "Saturday";
case DayOfWeek.Sunday:
return "Sunday";
}
}
}
보시다시피, DayOfWeek에 따라서 case가 결정되는건 알 수 있지만 조금 지저분하고 복잡하다고 느껴지기도 합니다.
그래서 나온것이 switch expression입니다.
간단히 말하여 switch를 식처럼 사용할 수 있는 기능이며, 사용법은 아래와 같습니다.
public static string GetDay()
{
return DateTime.Now.DayOfWeek switch
{
DayOfWeek.Monday => "Monday",
DayOfWeek.Tuesday => "Tuesday",
DayOfWeek.Wednesday => "Wednesday",
DayOfWeek.Thursday => "Thursday",
DayOfWeek.Friday => "Friday",
DayOfWeek.Saturday => "Saturday",
DayOfWeek.Sunday =>"Sunday",
};
}
토요일, 일요일을 묶어서 주말로 하고 싶으시다면 아래와 같이 or를 사용하여 묶을 수도 있습니다.
public static string GetDay()
{
return DateTime.Now.DayOfWeek switch
{
DayOfWeek.Monday => "Monday",
DayOfWeek.Tuesday => "Tuesday",
DayOfWeek.Wednesday => "Wednesday",
DayOfWeek.Thursday => "Thursday",
DayOfWeek.Friday => "Friday",
DayOfWeek.Saturday or DayOfWeek.Sunday =>"Weekend",
};
}
여기서 return은 그냥 return이고 중요한 부분은 이부분입니다.
return DateTime.Now.DayOfWeek switch
switch를 제어할 변수가 switch앞에 오고 뒤에는 소괄호 없이 바로 블럭이 오는 형태 입니다.
case문이 사라지고 (변수)=>(값) 형태로 바뀐것을 볼 수 있습니다.
그럼 default문은 어떻게 하느냐, 아래와 같이 _를 사용하여 나타낼 수 있습니다.
public static string GetDay()
{
return DateTime.Now.DayOfWeek switch
{
DayOfWeek.Monday => "Monday",
DayOfWeek.Tuesday => "Tuesday",
DayOfWeek.Wednesday => "Wednesday",
DayOfWeek.Thursday => "Thursday",
DayOfWeek.Friday => "Friday",
_ =>"Weekend",
};
}
아래와 같이 람다식으로도 쓸 수 있습니다.
public static string GetDay() => DateTime.Now.DayOfWeek switch
{
DayOfWeek.Monday => "Monday",
DayOfWeek.Tuesday => "Tuesday",
DayOfWeek.Wednesday => "Wednesday",
DayOfWeek.Thursday => "Thursday",
DayOfWeek.Friday => "Friday",
_ =>"Weekend",
};