본문 바로가기

C# 프로그래밍/문법 개념

[C#] 패턴 일치 (Pattern matching)

반응형

패턴 일치란?

패턴 일치란 스크립트 구조에 특정한 특징(패턴)이 있는지 확인하는 기법이다. 가장 대표적으로 사용되는 문법이 'is'와 'switch'식을  통한 패턴 매칭이다.

 

선언 패턴 식의 런타임 형식을 확인하고 일치가 성공하면 식 결과를 선언된 변수에 할당
형식 패턴 식의 런타임 형식을 확인. C# 9.0에 도입
상수 패턴 식 결과가 지정된 상수와 같은지 테스트
관계형 패턴 식 결과를 지정된 상수와 비교. C# 9.0에 도입
논리 패턴 식이 패턴의 논리적 조합과 일치하는지 테스트. C# 9.0에 도입
속성 패턴 식의 속성 또는 필드가 중첩 패턴과 일치하는지 테스트
위치 패턴 식 결과를 분해하고 결과 값이 중첩 패턴과 일치하는지 테스트
var 패턴 모든 식을 매칭하고 결과를 선언된 변수에 할당
무시 패턴 모든 식을 매칭
목록 패턴 시퀀스 요소가 해당 중첩 패턴과 일치하는지 테스트. C# 11에 도입

어떻게 사용할까?

패턴 매칭은 닷넷 버전이 업데이트될 때마다 추가되고 있다. 이 중 패턴 어휘로는 is와 switch가 주로 사용되므로, 두 문법을 기준으로 확인해보도록 하자.


is를 사용한 패턴

 


switch를 사용한 패턴

형식 패턴

이 패턴은 지정한 식과 일치하는 형식이 있는지 확인하는 식이다.

아래의 예시는 형식 패턴을 확인하기 위한 스크립트이며, 형식 패턴과 관련된 내용은 문단 최하단의 HowSpicy함수와 관련있다. 다음 예시를 살펴보자.

 

public class Food
{
    public string foodName;
    public string description;
    public Food(string _foodName, string _description)
    {
        foodName = _foodName;
        description = _description;
    }
}

기준이 되는 클래스인 Food 클래스를 선언하고 변수로 음식 이름과 설명을 넣어둔다.

 

아래는 Food 클래스를 상속받는 KoreanFood, JapaneseFood, ChineseFood에 관한 내용이다.

public class KoreanFood : Food
{
    public int wonPrice;

    public KoreanFood(string _foodName, string _description, int wonPrice) : base(_foodName, _description)
    {
        this.wonPrice = wonPrice;
    }
}

public class JapaneseFood : Food
{
    public int yenPrice;

    public JapaneseFood(string _foodName, string _description, int yenPrice) : base(_foodName, _description)
    {
        this.yenPrice = yenPrice;
    }
}

public class ChineseFood : Food
{
    public int yuanPrice;

    public ChineseFood(string _foodName, string _description, int yuanPrice) : base(_foodName, _description)
    {
        this.yuanPrice = yuanPrice;
    }
}

생성자를 사용해서 간단하게 초기화 할 수 있도록 한다.

 

아래는 FoodMaker라는 클래스이며 형식 패턴을 볼 수 있는 클래스이다.

public class FoodMaker : MonoBehaviour
{
    private readonly Food koreanKimchi = new KoreanFood("한국 김치", "원조. 맵고 맛있다.", 5500);
    private readonly Food japanesKimchi = new JapaneseFood("일본 김치", "맵지 않다.", 200);
    private readonly Food chineseKimchi = new ChineseFood("중국 김치", "...", 50);

    void Start()
    {
        int spicyGauge = HowSpicyIs(koreanKimchi);
        Debug.Log(koreanKimchi.foodName + " 맵기 정도: " + spicyGauge);

        spicyGauge = HowSpicyIs(japanesKimchi);
        Debug.Log(japanesKimchi.foodName + " 맵기 정도: " + spicyGauge);

        spicyGauge = HowSpicyIs(chineseKimchi);
        Debug.Log(chineseKimchi.foodName + " 맵기 정도: " + spicyGauge);
    }

    public int HowSpicyIs(Food food) => food switch
    {
        KoreanFood => 30,
        JapaneseFood => 15,
        ChineseFood => 10,
        _ => 0,
    };
}

각 클래스에 해당하는 인스턴스를 하나씩 생성하여준다. 

아래의 HowSpicyIs 함수는 Food타입의 변수를 매개변수로 받는데, 해당 타입과 일치하는 타입을 만나면 int값을 반환하게 된다. _=>은 switch case 문법에서 default와 같은 의미이다.

실행 결과

 

만약 형식패턴을 사용하지 않는다면 우리는 다음과 같이 작성해야 할 것이다!

public int HowSpicyIsByCase(Food food)
{
    int val = 0;
    if (food as KoreanFood != null)
    {
        val = 30;
    }
    else if (food as JapaneseFood != null)
    {
        val = 15;
    }
    else if (food as ChineseFood != null)
    {
        val = 10;
    }
    else
    {
        val = 40;
    }
    return val;
}

형식 패턴을 사용함으로써 더욱 직관적이고 간결한 표현을 할 수 있다.

반응형