前言
在 C# 7.0 新功能引進了基本的模式比對 (pattern matching) 功能,包含了 is 模式、switch 內使用 when 模式,與 解構 (desconstruction) 。而在 C# 8.0 新功能,對於這些功能進一步強化,其中包含:
1. Switch 運算式 (Switch Expressions)
2. 屬性模式 (Property Pattern)
3. Tuple 模式 (Tuple Pattern)
4. 位置模式 (Positional Pattern)
本篇文章簡單介紹這 4 種 pattern,若有任何錯誤或任何建議,請各位先進不吝提出,謝謝。
介紹
Switch 運算式 (Switch Expressions)
過去 switch 敘述句必須透過 case 區塊回傳結果,如下列程式碼所示:public static string TranslateStatus(Status playerStatus) { switch (playerStatus) { case Status.Actived: return "啟用"; case Status.Inactived: return "不啟用"; case Status.Archived: return "封存"; case Status.Maintained: return "維護"; default: throw new ArgumentException(message: "invalid enum value", paramName: nameof(Status)); }; }
其中, Status 是一個列舉資料格式:
public enum Status { Actived, Inactived, Archived, Maintained }
現在透過 switch expression,您可以使用較精簡的方式撰寫 switch (減少大量的 大括號、case 關鍵字 與 break 關鍵字),以下列程式為例:
public static string TranslateStatus(Status playerStatus) => playerStatus switch { Status.Actived => "啟用", Status.Inactived => "不啟用", Status.Archived => "封存", Status.Maintained => "維護", _ => throw new ArgumentException(message: "invalid enum value", paramName: nameof(Status)), };透過上列程式碼,您可以發現 switch 運算式有下列特色
1. 變數 (playerStatus) 移到 switch 關鍵字前
2. case 及 : 元素取代為 =>
3. default 取代為 _ 捨棄
4. 主體為運算式,而非陳述式
整體來說,語法呈現更加簡潔且直覺,若您使用 .NET Core 3.0 (或以上) 進行開發,不妨可以試試看 switch 運算式。
屬性模式 (Property Pattern)
顧名思義,在進行比對時您可以透過物件內的屬性進行比對。如下範例,我們有個 Address 物件,內部其中一個屬性是 City,我們能直接比對這個屬性:public static string CityCode(Address location) => location switch { { City: "Taipei" } => "1", { City: "Taichung" } => "4", { City: "Kaohsiung" } => "8", _ => "" };屬性模式可以讓您不用撰寫重複的物件名稱,直接取用內部屬性進行運算。透過此模式,上列程式碼看起來更加簡單且直覺。
Tuple 模式 (Tuple Pattern)
理所當然,若沒有建立類別 (class),但仍需要多個參數,這個時候您能透過 Tuple Pattern 方式進行比對,如下範例所示:public static string LogicalConjunction(string first, string second) => (first, second) switch { ("T", "T") => "T", ("T", "F") => "F", ("F", "T") => "F", ("F", "F") => "F", (_, _) => "invalid value" };這是一個 AND 的真值表,當輸入兩者為 T,則回傳 T;若為 T 與 F,則回傳 F;若兩者為 F,則回傳為 F。
位置模式 (Positional Pattern)
在 C# 7.0 您可以使用透過解構 (Deconstruct) 方式將本身的屬性指派為離散的變數。如下列程式為例,解構式內 out 參數即為解構後的變數。您可以在 23 行看見解構後 tuple。理所當然,可以指定不同數量的解構式,讓你的程式更有彈性。public class Leader { public string FirstName { get; set; } public string LastName { get; set; } public Leader(string firstName, string lastName) { FirstName = firstName; LastName = lastName; } public void Deconstruct(out string firstName, out string lastName) { firstName = FirstName; lastName = LastName; } } public static class CustomDeconstructorSample { public static string GetLeaderInfo(Leader l) { (string x, string y) = l; return x + " " + y; } }
解構的時候不需要帶參數 ?
依據 out 語法特性,可以忽略你不需要的參數
C# 7.0 解構指派方式並沒有任何模式 (pattern) 可以使用,純粹回傳 tuple 取得其項目。在 C# 8.0 ,若具有 tuple 或 解構式,即可使用位置模式 (不需要命名屬性) ,應用遞迴模式之嚴謹方式進行比對。
若物件 (object) 比對確定,則會透過解構式以巢狀模式 (nested pattern) 應用在結果值上。
以下面程式為例,我們宣告了兩個類別,分別是 Member 與 Leader,皆有 FirstName 與 Last Name 兩個屬性。另外, Member 多了一個屬性: Leader ...
public class Member { public string FirstName { get; set; } public string LastName { get; set; } public Leader Manager { get; set; } public Member(string firstName, string lastName, Leader manager) { FirstName = firstName; LastName = lastName; Manager = manager; } public void Deconstruct(out string firstName, out string lastName, out Leader manager) { firstName = FirstName; lastName = LastName; manager = Manager; } } public class Leader { public string FirstName { get; set; } public string LastName { get; set; } public Leader(string firstName, string lastName) { FirstName = firstName; LastName = lastName; } public void Deconstruct(out string firstName, out string lastName) { firstName = FirstName; lastName = LastName; } } public static class PositionalPatternSample { public static bool IsMember(Member m) { return m is Member(_, _, Leader(_, _)); } }
在 PositionalPatternSample 內的 IsMember 方法,可以看見我們對於內物件進行比對。你可以將 第 ? 行 Member 與 Leader 兩個類別名稱移除,透過位置模式直接進行比對 (如下程式)。
public static class PositionalPatternSample { public static bool IsMember(Member m) { return m is (_, _, (_, _)); } }
這是一個相當簡單的範例,雖然使用 if 敘述句有更好可讀性與可維護性,但使用 if 敘述句就沒有辦法達成遞迴比對的效果。
參考資料
1. Do more with patterns in C# 8.0 - .NET Blog
0 留言