再來也是個挺刺激的話題,pattern matching 在 C# 9.0 的增強。
環境
Visual Studio 2019 - 16.8.0 Preview 3.2
.NET 5.0.0-rc.1.20451.14
Visual Studio 2019 - 16.8.0 Preview 3.2
.NET 5.0.0-rc.1.20451.14
C# 9.0 帶來了幾個新的 pattern matching 擴充,分別為以下:
(1) Relational patterns
(2) Logical patterns
(3) Not patterns
(4) Simple type patterns
Relational patterns
Relational patterns 就是關係運算子 >、<、>= 和 >= 的運用,舉個簡單的需求,假設把矩形丟進一個函式,這個函式依賴 switch 分支依據其面積大小輸出特定字串。
先建立必要的介面與類別
class Rectangle
{
public double Width { get; set; }
public double Height { get; set; }
public double GetArea()
{
return Width * Height;
}
}
過去在 C# 8 我們得使用 when 子句:
static string Display8(Rectangle rect) => rect.GetArea() switch
{
double area when area < 10 => "小矩形",
double area when area >= 100 => "大矩形",
_ => "中矩形"
};
C# 9 的 relational patterns 則簡化的 when 子句的使用:
static string Display9(Rectangle rect) => rect.GetArea() switch
{
< 10 => "小矩形",
>= 100 => "大矩形",
_ => "中矩形"
};
再舉另外一個可以使用 relationl patterns 的例子,這個例子應用了好幾個 patterns 混合,我們要從一群學生中挑出分數超過七十分且為男性的學生:
interface IPerson
{
Guid ID { get; set; }
string Name { get; set; }
}
class Teacher : IPerson
{
public Guid ID { get; set; }
public string Name { get; set; }
public string Subject { get; set; }
}
class Student : IPerson
{
public Guid ID { get; set; }
public string Name { get; set; }
public bool IsPassed
{
get { return Score > 59; }
}
public Gender Gender { get; set; }
public int Score { get; set; }
}
public enum Gender
{
Male, Female
}
測試資料的內容如下:
new List<IPerson>
{
new Teacher {Name= "Bill" },
new Teacher {Name= "David"},
new Student{ Name = "魯夫", Gender = Gender.Male , Score= 60},
new Student{ Name = "妮可羅賓", Gender = Gender.Female , Score= 82},
new Student{ Name = "娜美", Gender = Gender.Female, Score= 70 },
new Student{ Name = "騙人布" ,Gender = Gender.Male, Score= 55 },
new Student{ Name = "香吉士", Gender = Gender.Male, Score= 58 },
new Student{ Name = "喬巴", Gender = Gender.Male, Score= 67 },
new Student{ Name = "布魯克", Gender = Gender.Male, Score= 99 },
new Student{ Name = "索隆", Gender = Gender.Male, Score= 80 },
new Student{ Gender = Gender.Male , Score= 60},
};
過去在 C# 8 你得這樣寫:
static IEnumerable<string> GetStudentOver70_8()
{
var people = Create();
foreach (var p in people)
{
if (p is Student { Gender: Gender.Male, Name: string name, Score: int score } && score > 70)
{
yield return name;
}
}
}
C# 9 有了 relational patterns 後你可以這樣寫:
static IEnumerable<string> GetStudentOver70_9()
{
var people = Create();
foreach (var p in people)
{
if (p is Student { Gender: Gender.Male, Name: string name, Score: > 70 })
{
yield return name;
}
}
}
簡單多了,對吧。
Logical patterns
Logical patterns 說來就是可以在 patterns matching 的語法內組合 and、or 和 not 運算子,很有趣的是它並沒有採用過去習慣的 &&、|| 和 ! 來表示。
拿上一個學生分數的例子,做一個無聊的例題,找出 >=90 或 < 10 分的給予 "特別高或特別低";剩下的則給"一般",程式碼如下:
class Program
{
static void Main(string[] args)
{
foreach (var student in Create())
{
Console.WriteLine($"{student.Name} is {GetGrades(student)}");
}
}
static string GetGrades(Student student) => student.Score switch
{
>=90 or <10 => "特別高或特別低",
_ => "一般"
};
static List<Student> Create()
{
return new List<Student>
{
new Student{ Name = "魯夫", Gender = Gender.Male , Score= 5},
new Student{ Name = "妮可羅賓", Gender = Gender.Female , Score= 82},
new Student{ Name = "娜美", Gender = Gender.Female, Score= 70 },
new Student{ Name = "騙人布" ,Gender = Gender.Male, Score= 55 },
new Student{ Name = "香吉士", Gender = Gender.Male, Score= 58 },
new Student{ Name = "喬巴", Gender = Gender.Male, Score= 67 },
new Student{ Name = "布魯克", Gender = Gender.Male, Score= 99 },
new Student{ Name = "索隆", Gender = Gender.Male, Score= 80 },
};
}
}
另外兩個我們下次再聊。
參考資料:模式比對增強功能