3 minute read

개요

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", 
};


Top