프로그래밍 관련/C#

C# 메모. 패턴 매칭(Pattern Matching)

LAYER6AI 2019. 4. 7. 10:49

패턴이 있는 Is 표현식(Is-expressions with patterns)

아래 예제에서는 상수 패턴(const pattern)과 타입 패턴(type pattern)을 사용한 표현식을 볼 수 있다. 

public void PrintStars(object o)
{
    if (o is null) return;     // 상수 패턴 "null"
    if (!(o is int i)) return; // 타입 패턴 "int i"
    WriteLine(new string('*', i));
}

위 예제를 보면 패턴 변수라는 녀석이 등장한다. 표현식 중간에서 패턴 변수를 선언할 수 있고, 자신을 둘러싸고 있는 블럭 내에서 사용할 수도 있는 것을 볼 수 있다. 전에 만나봤던 out 변수란 녀석과 비슷하다.


패턴을 Try로 시작하는 메서드와 같이 사용할 때는 아래와 같이 유용하게 쓰일 수도 있다.

if (o is int i || (o is string s && int.TryParse(s, out i)) { /* i 사용 */ }

패턴이 있는 switch문(Switch statements with patterns)

C# 7.0에서는 switch문에 기본 타입 뿐만 아니라, 모든 타입을 패턴 매칭을 위해 사용할 수 있게 되었다. case 절에서도 패턴을 사용할 수 있으며, 아래와 같이 when문을 통해 다른 조건을 추가할 수도 있게 되었다.

case (expr) when (when-condition):

예제를 직접 보도록 하자.

switch(shape)
{
    case Circle c:
        WriteLine($"반지름이 {c.Radius}인 원");
        break;
    case Rectangle s when (s.Length == s.Height):
        WriteLine($"{s.Length} x {s.Height} 정사각형");
        break;
    case Rectangle r:
        WriteLine($"{r.Length} x {r.Height} 직사각형");
        break;
    default:
        WriteLine("<알 수 없는 모양>");
        break;
    case null:
        throw new ArgumentNullException(nameof(shape));
}

위의 예제에서 몇 가지 주의해야 할 점이 있다.

  • default 절은 항상 마지막에 검사한다. 위 예제처럼 null 절이 마지막에 오더라도, default 절을 검사하기 전에 null 절을 먼저 검사한다. 이는 기존의 switch문과 똑같다.
  • 마지막에 있는 null 절에는 도달할 수 없다. 암시적 null 검사가 있기 때문에 어떤 형식 패턴이 먼저 오더라도 실수로 잡아채는 일을 막아준다. 예를 들어서, shape가 null인 Circle 객체일 경우 첫 번째에 있는 case 절이 그것을 잡아 c.Radius에서 NullReferenceException 예외가 발생하는 경우를 막아준다는 것이다.  
  • 기존의 switch문과 같이 순서가 중요하다. 만약에, shape가 정사각형인지 검사하는 case 절을 아래로 내려버리면 정사각형인데도 불구하고 직사각형이라고 출력되는 결과를 볼 수 있을 것이다. 개발자가 실수로 그러한 일을 하더라도, 컴파일러에서 이전 case에서 이미 처리되었다는 에러를 내보낸다.

여기서 case ...: 레이블에 들어간 패턴 변수는 해당 swtich 영역 범위에서만 사용할 수 있다는 것도 확인할 수 있다.