패턴 매칭
- 식의 결과가 특정 패턴(형태)와 일치하는지 검사하는 것
- 장황하고 거추장 스러운 분기문을 간결하게 할 수 있음
1) 선언 패턴
- 주어진 식이 특졍 형식 (EX. int, string 등) 과 일치하는지를 평가
object foo = 23;
if(foo is int bar) //변수 bar를 선언
{
Console.WriteLine(bar);
}
- foo 식이 int와 일치하는지 판단하고 bar 변수를 선언함
- bar는 해당 scope내에서 사용 가능
2) 형식 패턴
- 형식 패턴은 선언 패턴과 거의 같은 방식으로 동작
- 단, 변수 생성 없이 형식 일치 여부만 테스트
object foo = 23;
if(foo is int) //foo가 int 형식인지만 판단
{
Console.WriteLine(foo);
}
3) 상수 패턴
- 식이 특정 상수와 일치하는지를 검사
var GetCountryCode = (string nation) => nation switch
{
"KR" => 82,
"US" => 1,
"UK" => 44,
_ => throw new ArgumentException("Not supported Code")
};
Console.WriteLine(GetContryCode("KR"));
Console.WriteLine(GetContryCode("US"));
Console.WriteLine(GetContryCode("UK"));
4) 프로퍼티 패턴
- 식의 속성이나 필드가 패턴과 일치하는지를 검사
class Car
{
public string Model { get; set; }
public DateTime ProducedAt{ get; set; }
}
static string GetNickname(Car car)
{
var GenerateMessage = (Car car, string nickname) =>
$"{car.Model} produced in {car.ProduceAt.Year} is {nickname}";
if(car is Car { Model:"Mustang", ProducedAt.Year:1967})
return GenerateMessage(car, "Fastback");
else if (car is Car { Model:"Mustang", ProducedAt.Year:1976})
return GenerateMessage(car, "Cobra II");
else
return GenerateMessage(car, "Unknown");
}
- car 객체가 해당 프로퍼티 패턴과 일치하는지 검사
5) 관계 패턴
- 관계 연산자를 이용하여 입력받은 식을 상수와 비교
- 관계 연산자 : >, >=, ==, !=, <, <=
static string GetGrade(double score) => score switch
{
< 60 => "F",
>= 60 and < 70 => "D",
>= 70 and < 80 => "C",
>= 80 and < 90 => "B",
_ => "A",
};
6) 논리 패턴
- 복수의 패턴을 패턴 논리 연산자(and, or, not)로 조합
class OrderItem
{
public int Amount{ get; set; }
public int Price { get; set; }
}
static double GetPrice(OrderItem orderItem) => orderItem switch
{
OrderItem { Amount: 0 } or OrderItem { Price: 0 }
=> 0.0,
OrderItem { Amount: >= 0 } or OrderItem { Price: >= 10_000 }
=> orderItem.Amount * orderItem.Price * 0.8,
not OrderItem { Amount: < 100 }
=> orderItem.Amount * orderItem.Price * 0.9,
_ => orderItem.Amount * orderItem.Price,
};
7) 괄호 패턴
- 괄호 ()로 패턴을 감쌈
object age = 30;
if(age is (int and >19))
Console.WriteLine("Major");
8) 위치 패턴
- 식의 결과를 분해(Deconstruct)하고, 분해된 값들이 내장된 복수의 패턴과 일치하는지를 검사
- 내장되는 패턴에는 형식 패턴, 상수 패턴 등 모든 패턴 사용 가능
Tuple<string, int> itemPrice = new Tuple<string, int>("espresso", 3000);
if( itemPrice is ("espresso", < 5000))
{
Console.WriteLine("The coffee is affordable.");
}
9) var 패턴
- null을 포함한 모든 식의 패턴 매칭을 성공시키고, 그 식의 결과를 변수에 할당
- 식의 결과를 임시 변수에 할당한 다음 추가적인 연산을 수행하고자 할 때 유용
//평균이 60점 이상인 경우에만 Pass
var IsPassed =
(int[] scores) => scores.Sum() / scores.Length is var average
&& average >= 60;
int[] scores1 = { 90, 80, 60, 80, 70 };
Console.WriteLine($"{string.Join(",", scores1)}: Pass:{IsPassed(scores1)}" //true
int[] scores2 = { 90, 80, 59, 80, 70};
Console.WriteLine($"{string.Join(",", scores2)}: Pass:{IsPassed(scores2)}" //false
10) 무시 패턴
- var 패턴처럼 모든 식과의 패턴 일치 검사를 성공
- 단, is 식에서는 사용할 수 없고, switch 식에서만 사용 가능
var GetCountryCode = (string nation) => nation switch
{
"KR" => 82,
"US" => 1,
"UK" => 44,
_ => throw new ArgumentException("Not supported Code")
};
Console.WriteLine(GetContryCode("KR"));
Console.WriteLine(GetContryCode("US"));
Console.WriteLine(GetContryCode("UK"));
11) 목록 패턴
- 배열이나 리스트(List)가 패턴의 시퀀스와 일치하는지를 검사
- 패턴의 시퀀스는 ' [ ' 와 ' ] ' 사이에 패턴의 목록을 입력하여 생성
var match = (int[] array) => array is [int, >10, _];
Console.WriteLine(match(new int[] { 1, 100, 3 })); //True
Console.WriteLine(match(new int[] { 100, 10, 999 } //False
var match = (int[] array) => array is [int, >10, ..];
Console.WriteLine(match(new int[] { 1, 100, 101, 102, 103, 104 })); //True
Console.WriteLine(match(new int[] { 100, 10, 999 } //False