[2025-02-23] - 게시글 최초 작성
1. 패턴 매칭이란?
어떤 식이 특정 패턴과 일치하는지 검사.
2. 패턴 매칭
2.1 선언 패턴
주어진 식이 특정 형식과 일치하는지 평가
1. 식이 주어진 형식과 일치하는지 테스트
2. 테스트가 성공하면 식을 주어진 형식으로 변환
/*
* 1. obj가 int인 경우
* 2. obj가 int형식으로 변환하여 bar에 할당
*/
if (obj is int bar)
{
Console.WriteLine(bar);
}
2.2 형식 패턴
선언 패턴과 거의 같은 방식으로 동작, 변수 생성 없이 형식 일치 여부만 테스트
object obj = 23;
if (obj is int)
{
Console.WriteLine(obj);
}
class Preschooler { }
class Underage { }
class Adult { }
class Senior { }
class Program
{
static int CalculateFee(object visitor)
{
return visitor switch
{
Underage => 100,
Adult => 500,
Senior => 200,
_ => throw new ArgumentException($"Prohibited age : {visitor.GetType()}", nameof(visitor)),
};
}
internal async Task Main()
{
Console.WriteLine($"{CalculateFee(new Senior())}");
}
}
2.3 상수 패턴
식이 특정 상수와 일치하는지 여부를 검사.
internal async Task Main()
{
var GetContryCode = (string nation) => nation switch
{
"KR" => 82,
"US" => 1,
"UK" => 44,
_ => throw new ArgumentException {"Not Supported Code"}
};
Console.WriteLine(GetContryCode("KR"));
}
2.4 프로퍼티 패턴
식의 속성이나 필드가 패턴과 일치하는지를 검사 ( int, double 등과 같은 기본 데이터 형식이 아닐 경우 유용 )
// Version C# 11.0
class Car
{
public string Model { get; set; }
public DateTime ProduceAt { get; set; }
}
class Program
{
static string GetNickName(Car car)
{
var Message = (Car car, string nickName) =>
$"{car.Model} produced in {car.ProduceAt.Year} is {nickName}";
if (car is Car { Model: "Mustang", ProduceAt.Year: 1967 })
return Message(car, "Fastcak");
else if (car is Car { Model: "Mustang", ProduceAt.Year: 1976 })
return Message(car, "Cobra II");
else
return Message(car, "Unknown");
}
/*
static string GetNickName(Car car)
{
var nickName = car switch
{
{Model:"Mustang", ProduceAt.Year:1967 } => "FastBack",
{ Model: "Mustang", ProduceAt.Year: 1976 } => "Cobra II",
_ => "Unknown"
};
return $"{car.Model} produced in {car.ProduceAt.Year} is {nickName}";
}
*/
internal async Task Main()
{
Console.WriteLine(GetNickName(new Car() { Model = "Mustang", ProduceAt = new DateTime(1967, 11, 23) }));
}
}
2.5 관계 패턴
관계 연산자를 이용하여 입력받은 식을 상수와 비교
static int IsPassed(double score) => score switch
{
< 60 => false,
_ => true,
}
static string GetGrade(double score) => score switch
{
< 60 => "F",
>= 60 and < 70 => "D",
>= 70 and < 80 => "C",
>= 80 and < 90 => "B",
_ => "A",
}
2.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: >= 100} and OrderItem { Price: >= 10_000 }
=> orderItem.Amount * orderItem.Price * 0.8,
not OrderItm { Amount: < 100 }
=> orderItem.Amount * orderItem.Price * 0.9,
_ => orderItem.Amount * orderItem.Price,
}
internal async Task Main()
{
Console.WriteLine(GetPrice(new OrderItem() { Amount = 0, Price = 10_000 }));
}
2.7 괄호 패턴
소괄호 () 로 패턴을 감싼다.
보통 논리 패턴으로 여러 패턴을 조합한 뒤 이를 새로운 패턴으로 만드는 경우 사용
// To Version C# 9.0
object obj = 30;
if (obj is (int and > 19))
Console.WriteLine("Major");
2.8 위치 패턴
식의 결과를 분해하고, 분해된 값들이 내장된 복수의 패턴과 일치하는지를 검사
위치 패턴 안에 내장되는 패턴에는 형식 패턴, 상수 패턴 등 어떤 패턴도 가능
Tuple<string, int> itemPrice = new Tuple<string, int>("espresso", 3_000);
if (itemPrice is ("espresso", < 5_000))
{
Console.WriteLine("Hello");
}
struct Audience
{
public bool IsCitizen { get; init; }
public int Age { get; init; }
public Audience(bool isCitizen, int age)
{
IsCitizen = isCitizen;
Age = age;
}
public void Deconstruct(out bool isCitizen, out int age)
{
isCitizen = IsCitizen;
age = Age;
}
}
static void Main(string[] args)
{
var CalculateFee = (Audience audience) => audience switch
{
(true, < 19) => 100,
(true, _) => 200,
(false, < 19) => 200,
(false, _) => 400,
};
}
2.9 var 패턴
null을 포함한 모든 식의 패턴을 매칭을 성공시키고, 그 식의 결과를 변수에 할당
// 모든 과목이 60점이 넘고, 평균이 60점 이상인 경우에만 Pass
var IsPassed = (int[] scores) => scores.Sum() / scores.Length is var average
&& Array.TrueForAll(scores, (score) => score >= 60)
&& average >= 60;
2.10 무시 패턴
var 패턴처런 모든 식과의 패턴 일치 검사를 성공.
is식에서는 사용 불가! switch 식에서만 사용 가능
var GetCountryCode = (string nation) => nation switch
{
"KR" => 82,
"US" => 1,
"UK" => 44,
_ => throw new ArgumentException("Not Support Code") // 무시 패턴 매칭
};
2.11 목록 패턴
배열이나 리스트가 패턴의 시퀀스가 일치하는지를 검사
// 예시 1
var match1 = (int[] array) => array is [int, 10, _];
Console.WriteLine(match1(new int[] { 1, 100, 3 })); // True
Console.WriteLine(match1(new int[] { 100, 10, 999 })); // False
// 예시 2
var match2 = (int[] array) => array is [int, > 10, ..];
Console.WriteLine(match2(new int[] { 1, 100, 3 })); // True
Console.WriteLine(match2(new int[] { 100, 10, 999 })); // False
// 예시 3
var GetStatics = (List <object[]> records) =>
{
var statics = new Dictionary<string, int>();
foreach(var record in records)
{
var (contentType, contentViews) => record switch
{
[_, "COMEDY", .., var views] => ("COMEDY", views),
[_, "SF", .., var views] => ("COMEDY", views),
[_, "ACTION", .., var views] => ("COMEDY", views),
[_, .., var amount] => ("COMEDY", amount),
_ => ("ETC", 0),
}
}
}