패턴 일치?
패턴 일치라는 것은 어떤 대상이 특정한 특징, 즉 패턴을 가지고 있는지 테스트하는 것이다.
패턴 일치를 찾아보고 느낀 것이 설명이 뭔가 모호하다 해야할까나?
뭔가 설명해주는데 말이 어렵다.
그 이유는 패턴 일치라는 것이 추상적 의미이기 때문이다.
최대한 직관적이게 설명하자면 객체 컬렉션으로부터 내 조건에 맞는 객체들만 추출해내기 위해 객체에다 그 조건을 검사하는 것이다.
보통은 ==
연산자를 사용하여 조건을 체크할 것이다.
우리가 평소 nullable
에서 하던 null
검사도 패턴일치이다.
패턴 일치의 종류
패턴 일치의 종류는 세 가지가 있다.
- 상수 패턴 (Const Pattern)
- 선언 패턴 (Declaration Pattern)
- var 패턴 (var Pattern)
1. 상수 패턴 (Const Pattern)
상수 패턴은 특정 상수값, 즉 지원되는 리터럴과 일치 비교를 한다.
- 각종 숫자형 (
int
,float
등등)
string
,char
bool
enum
const
null
해당 자료형의 리터럴과 일치하는지 여부를 검사하는 것이다.
상수 패턴의 is
초기의 C#에서는 주로 ==
를 사용했다.
하지만 C# 7.0 부터 is에 기능이 추가되면서 is를 상수 패턴으로 사용이 가능해졌다.
// numeric
var intVal = int.MaxValue;
Console.WriteLine($"{nameof(intVal)} {intVal is 1000000}");
2. 선언 패턴 (Declaration Pattern)
선언 패턴은 그 객체가 어떤 특정 클래스인지, 상속된 자식 클래스인지, 인터페이스를 상속 받았는지 등의 검사를 하는 것이다.
타입 패턴 (Type Pattern)이라고도 한다.
선언 패턴은 다음의 패턴들을 체크한다.
- 값의 타입이 T
- 값의 타입이 T를 상속 (class)
- 값의 타입이 T를 구현 (interface)
- 값의 타입이 T로 암시적 참조 변환을 지원
- 값의 타입이 nullable value T? 일때 T 혹은 null
- 값의 타입이 boxing 혹은 unboxing을 통해 T 타입으로 변경 가능
선언 패턴의 is
선언 패턴 역시 C# 7.0부터 기능이 추가된 is
를 이용해 테스트가 가능하다.
object[] data = { 1, null, 10, new Circle(5), new Person("Lee"), "" };
foreach (object item in data)
{
if (item is Circle circ) // type pattern
{
WriteLine(circ.Radius);
}
}
3. var 패턴 (var Pattern)
선언 패턴에서 그 타입만 var로 바꾼 것이다.
어라, 그러면 is var
는 항상 참이지 않은가?
그래서 var 패턴
은 신기한 것을 쓴다.
switch를 이용한 패턴 일치
여기서 switch
는 분기를 위한 문이 아니다.
이 역시 C# 7.0 부터 패턴 일치를 위해 추가된 기능의 switch
이다.
foreach (var shape in shapes)
{
switch (shape)
{
// const pattern
case null:
WriteLine("Skip");
break;
// type pattern
case Circle c:
WriteLine($"원: {c.Radius * c.Radius * Math.PI}");
break;
case Rect r when r.Width == r.Height:
WriteLine($"정사각형: {r.Width * r.Width}");
break;
case Rect r:
WriteLine($"사각형: {r2.Width * r2.Height}");
break;
default:
WriteLine("모르는 모양");
break;
}
}
C# 8.0 이후의 switch 패턴 일치
static int GetSourceLabel<T>(IEnumerable<T> source) => source switch
{
Array array => 1,
ICollection<T> collection => 2,
_ => 3,
};
코드가 골때린다.
switch
를 이용한 패턴 일치를 통해
해당 패턴에 맞는 값을 =>
를 이용해 골라서 반환해줄 수가 있다.
사용 예를 좀더 첨부하겠다.
public static decimal GetGroupTicketPrice(int visitorCount) => visitorCount switch
{
1 => 12.0m,
2 => 20.0m,
3 => 27.0m,
4 => 32.0m,
0 => 0.0m,
_ => throw new ArgumentException($"Not supported number of visitors: {visitorCount}", nameof(visitorCount)),
};
public record Point(int X, int Y);
static Point Transform(Point point) => point switch
{
var (x, y) when x < y => new Point(-x, y),
var (x, y) when x > y => new Point(x, -y),
var (x, y) => new Point(x, y),
};
static void TestTransform()
{
Console.WriteLine(Transform(new Point(1, 2))); // output: Point { X = -1, Y = 2 }
Console.WriteLine(Transform(new Point(5, 2))); // output: Point { X = 5, Y = -2 }
}
public decimal CalculateDiscount(Order order) =>
order switch
{
{ Items: > 10, Cost: > 1000.00m } => 0.10m,
{ Items: > 5, Cost: > 500.00m } => 0.05m,
{ Cost: > 250.00m } => 0.02m,
null => throw new ArgumentNullException(nameof(order), "Can't calculate discount on null order"),
var someObject => 0m,
};
이외에도 무궁무진으로 활용할 수 있다.
C# 9.0, C# 10.0 까지도 패턴 일치 관련 기능이 추가가 되었다.
못다루는 패턴과 C# 기능에 대해선 다음 문서들을 참고하는 것이 좋겠다.
Uploaded by N2T
'개발 > Unity 내일배움캠프 TIL' 카테고리의 다른 글
Unity2D 플레이어 캐릭터 이동 구현하기 (0) | 2023.09.05 |
---|---|
Unity MonoBehaviour (모노비헤이비어)와 스크립트 라이프 사이클 (1) | 2023.09.04 |
C# 중첩 클래스와 partial 클래스 (0) | 2023.08.31 |
C# Enumerable 인터페이스 (0) | 2023.08.30 |
C# Action으로 종속성 없애기..? (0) | 2023.08.29 |