본문 바로가기

진리는어디에/C#

[C#] switch expression in 8.0

C# 8.0 부터 추가된 switch expression에 대해서 알아 보도록 하겠다. 이번 포스트는 문법 보다는 개념적인 부분을 많이 다루려 한다. 가장 먼저 '문(statement)'와 비교하여 '표현식(expression)'이 무엇인지 개념에 대해 살펴보고, 기존 switch statement와 switch expression의 개념적 차이에 대해서 살펴 본다.
개념을 간단히 이해한 후 switch expression의 활용 방안에 대해 본격적으로 알아 보도록 하자.

문? vs 표현식?

C# 8.0에는 switch statement에 이어 switch expression이 추가 되었다. 먼저 statement와 expression의 차이를 알아 보자.

Statement(문, 문장)

프로그램을 구성하는 기본 요소로써 언어에 따라 정의가 다르긴 하지만 C#에서는 세미콜론(;)으로 종료되는 일반적인 문장을 모두 Statement라고 한다.

int a = 10; // statement

Expression(표현식)

  • 하나의 값으로 계산되는 식
  • 연산자와 피연산자로 구성
  • return을 표기하지 않아도 하나의 값으로 반환

예를 들어 1+2는 3이라는 하나의 값으로 계산 된다. 이것은 '표현식'이다. 다시 1+2*3이라고하면 이 또한 하나의 값으로 계산 되는 표현식이다. 

swith 문 vs 표현식

그렇다면 위 개념에 근거하여 기존 switch 문을 살펴보자. 전통적인 switch 문은 아래 처럼 switch문 안에 필수적으로 각조건을 조사하는 case문이 필요했다.

// 전통적인 switch case
int n = 50;
int s = 0;

switch(n)
{
    case 10 :
        s = 11;
        break;
    case 20 :
        s = 22;
        break;
    case 30 :
        s = 33;
        break;
    default :
        s = 100;
        break;
}

Console.WriteLine(s);   // 100, 조건에 해당하는 값이 없어 default 선택

(쓰고 보니 세미콜론도 없고..뭔가 statement가 아닌거 아니냐고 물을 수도 있는데 기분탓이다. 이거 statement맞다. MS 도큐먼트에서도 그렇게 이야기 했다. 암튼 그렇다.)

그렇다면 switch expression을 살펴 보자.

int n = 50;

int s = n switch
{
    10 => 11,
    20 => 22,
    30 => 33,
    _ => 100            // default
};

Console.WriteLine(s);   // 100, 조건에 해당하는 값이 없어 default 선택

case문대신 => 연산자로 대체되었고 default 케이스 대신 언더바(_)가 사용 되었다. 코드 스타일에 대한 선호야 호불호가 나뉘는 부분이지만 확실히 코드가 간결해졌다. 

활용

아래 처럼 도형을 나타내는 세 가지 클래스가 있다고 가정하고 타입 패턴 매칭을 기존의 switch 문과 8.0 부터 추가된 switch 표현식을 사용하는 예제를 살펴 보도록 하자.

class Shape {}

class Circle : Shape
{
    public double radious = 100;
}

class Rectangle : Shape
{
    public double width = 100;
    public double height = 100;
}

class Point : Shape
{
    public double x = 0;
    public double y = 0;
}

class Program
{
    public static void Main()
    {
        Shape s = new Circle();
        
        // 전통적인 switch 문을 이용한 type pattern matching
        double area1 = 0;
        switch (s)
        {
            case null:
                area1 = 0;
                break;
            case Point p :
                area1 = 0;
                break;
            case Circle c:
                area1 = Math.PI * c.radious * c.radious;
                break;
            case Rectangle r:
                area1 = r.width * r.height;
                break;
            default:
                area1 = 0;
                break;
        }
        
        // 8.0 부터 추가된 switch 표현식을 이용한 type pattern matching
        double area2 = s switch
        {
            null => 0,          // const pattern matching
            Point p => 0,
            Circle c => Math.PI * c.radious * c.radious,
            Rectangle r => r.width * r.height,
            _ => 0
        };

switch 표현식의 코드가 훨씬더 간결한 것을 확인 할 수 있다. 이는 튜플 패턴 매칭에서 더욱 두드러진다.

// tuple pattern
int value1 = 0;
int value2 = 0;

int ret1 = 0;
switch (value1, value2)
{
    case ValueTuple<int, int> t when t.Item1 == 0 && t.Item2 == 0:
    // case (0, 0) :
        ret1 = 0;
        break;
    //case ValueTuple<int, int> t  when t.Item1 > 100:
    case var(a, b) when a > 100:   // 주석과 동일한 의미다
        ret1 = 100;
        break;
    //case ValueTuple<int, int> t when t.Item1 <= 100 && t.Item2 > 100:
    case (int a, int b) when a <= 100 && b > 100: // 주석과 동일한 의미다
        ret1 = 200;
        break;
    default:
        ret1 = 300;
        break;
}

int ret2 = (value1, value2) switch
{
    (0, 0) => 0,
    var (a, b) when a > 100 => 100,
    var (a, b) when a <= 100 && b > 100 => 200,
    _ => 300
};

마치며

이상으로 C# 8.0에 추가된 switch expression에 대해 알아 보았다. 딱히 기술적인 개념이 들어간 것이 아니라 코드를 좀더 간결하게 사용할 수 있는 방법이므로 이해하는데 큰 어려움은 없었으리라 생각한다. 새로운 버전이 추가 될때 마다 새로운 표현식이 추가 되는데 알고 보면 쉽지만 모르고 봤을 때는 당황스럽기 때문에 이번 포스트를 추가 했다. 기본 문법만 익히도록 하고 나중에 어디가서 8.0 문법을 보더라도 당황하지 말길 바란다.

유익한 글이었다면 공감(❤) 버튼 꾹!! 추가 문의 사항은 댓글로!!