C# 7.0 新特性3: 模式匹配

来源:http://www.cnblogs.com/ylvict/archive/2016/06/15/5588613.html
-Advertisement-
Play Games

本文參考Roslyn項目Issue:#206,及Docs:#patterns。 1. C# 7.0 新特性1: 基於Tuple的“多”返回值方法 2. C# 7.0 新特性2: 本地方法 3. C# 7.0 新特性3: 模式匹配 模式匹配也許能算的上C#本次更新最重量級的升級,也是最受關註的特性(也 ...


本文參考Roslyn項目Issue:#206,及Docs:#patterns

 

  1. C# 7.0 新特性1: 基於Tuple的“多”返回值方法

  2. C# 7.0 新特性2: 本地方法

  3. C# 7.0 新特性3: 模式匹配

 

模式匹配也許能算的上C#本次更新最重量級的升級,也是最受關註的特性(也許沒有之一),通過模式匹配,我們可以簡化大量的條件代碼。

 

Switch語句

大家也許遇到過這樣的情景,假設你的代碼中,有一個Nullable<int>的值,需要對其在正整數非正整數Null三種情況下分別作不同的邏輯處理。大多數童鞋直接想到是類似於下麵的邏輯:

1 void Foo(int? num)
2 {
3     if (!num.HasValue)
4      /* null logic */
5     else if (num.Value > 0)
6      /* positive int logic */
7     else
8      /* negative int & zero logic */
9 }
View Code

請大家思考一下,這個邏輯是否可以用switch-case語句來做,在VB及很多非C系的語言中,答案是肯定的,比如VB.NET中可以這樣寫:

 1 Sub Foo(Num As Integer?)
 2     Select Case Num
 3         Case Not Num.HasValue
 4         'null logic
 5         Case Num > 0
 6         'positive Int logic
 7         Case Num <= 0
 8             'negative Int() & zero logic
 9         Case Else
10 
11     End Select
12 End Sub
View Code

說到這裡,在具體討論模式匹配在switch-case中的應用之前,先淡淡的吐槽一下C#,本來理所應當的一個簡單的小語法,到了C#7.0才加入。

看看C#7.0加入的類型模式(Type Pattern):

 

 1 void Foo(int? num)
 2 {
 3     switch (num)
 4     {
 5         case null:
 6             //null logic
 7             break;
 8         case int n when n > 0:
 9             //positive Int logic
10             break;
11         case int n when n <= 0:
12             //negative Int() & zero logic
13             break;
14     }
15 }

 

這個不多說了,大家自己體會,單純的在Nullable<int>下,可能體現的不是很清晰,個人認為這個小變動其實意義並不是很大,同樣場景下,或許if-if else-else會讓代碼更清晰易讀些。

 

如果說模式匹配僅僅是完善了一下switch-case,那可真是太大才小用了,下麵我們看一個好玩的。 

Match表達式

雖然把match帶到C#中看起來並不是什麼大事,但是會引起的代碼簡化還是非常爽的。

就像很多人說三元表達式(<condition>?<true result> : <false result> )將if-else簡化一樣。match表達式,是將switch-case結構簡化到了一個新限度。

看match表達式代碼前,我們先來看一行略坑的三元表達式。

var reuslt = x == null ? default(int) : (x is Func<int> ? (x as Func<int>)() : (x is int ? Convert.ToInt32(x) : default(int)));

好吧,我承認我是故意讓你們抓狂的。^_^, 為了能穩住大家看完上面這行代碼後的情緒,來一副match表達式消消火。

var result = x match(
    case Func<int> f: f(),
    case int i: i,
    case *: default(int)
);

這兩種寫法效果上是等效的,有沒有非常乾凈清爽的感覺?寫過match表達式的碼農,應該再也不想回去嵌套 <*>?<*>:<*> 了。 (註:目前這種寫法還未確認,C#7.0發佈後可能會有略微變動

 

Is表達式

如果說上面兩個變化是“語法糖”,那麼is表達式可是要玩真的了。

說點題外話,其實對正則表達式熟悉的童鞋可能知道,本質上[模式匹配]和正則表達式要解決的問題邏輯類似,以一個確定的模式,來判斷或查找一個確定的實例。只不過在正則表達式中,這裡說的"模式"是正則表達式,"實例"指字元串。而[模式匹配]下,所針對的"實例"是對象,那麼"模式",就可以理解成is表達式了。

舉個例子,比如你要查找併列出 一組電子設備中,所有iPhone的IMEI串號,我們在C#6.0中,會這樣做:

 1 class Device
 2 {
 3     public ProductLineOption ProductLine { get; set; }
 4 }
 5 
 6 class MobiePhone : Device
 7 {
 8     public string IMEICode { get; set; }
 9 }
10 
11 IEnumerable<Device> GetAllDevices() { /* 獲取並返回所有設備 */ };
12 
13 IEnumerable<string> GetAlliPhoneIMEI()
14 {
15     var deviceList = this.GetAllDevices();
16     foreach (Device device in deviceList)
17     {
18         MobiePhone phone = device as MobiePhone;
19         if (phone == null) continue;
20 
21         if (phone.ProductLine == ProductLineOption.IPhone)
22         {
23             yield return phone.IMEICode;
24         }
25     }
26 }

一個非常典型的傳統方法,沒什麼好說的。我們直接來看C#7.0 中 is表達式怎麼等效的實現這段邏輯:

 1 IEnumerable<string> GetAlliPhoneIMEI()
 2 {
 3     List<Device> deviceList = this.GetAllDevices();
 4     foreach (Device device in deviceList)
 5     {
 6         if (device is MobiePhone { IMEICode is var imei, ProductLine is ProductLineOption.IPhone})
 7         {
 8             yield return imei;
 9         }
10     }
11 }

如果你還是覺得這沒什麼,那麼,其實這個例子中,僅僅體現出模式匹配中的屬性模式

根據Doc:#patterns C#7.0會提供一下幾種匹配方式:

  • 類型模式
  • 常量模式
  • 變數模式
  • 通配符模式
  • 位置模式
  • 屬性模式

我們可以想象,如果模式匹配組合起來使用,會給現有的C#代碼打來多大的便利和清靜。

Okay,說了這麼多,下麵給大家一個相對完整的案例,自行體會。

 

案例 

 1 abstract class Animal
 2 {
 3     public string Name { get; set; }
 4 }
 5 
 6 class Dog : Animal
 7 {
 8     public string BarkLikeCrazy() => "WOOF WOOF WOOF";
 9 }
10 
11 class Cat : Animal { }
12 class Swan : Animal { }
13 
14 class Program
15 {
16     static void Main(string[] args)
17     {
18         var animals = new Animal[] {
19             new Dog { Name = "hola" },
20             new Cat { Name = "tom" },
21             new Swan { Name = "hacienda" }
22         };
23 
24         var organizedAnimals = from animal in animals
25                                let sound = animal match( //Match語句
26                                    case Dog d: "woof... " + d.BarkLikeCrazy(), //類型匹配
27                                    case Cat c: "meow",
28                                    case * : "I'm mute.." //通配符匹配
29                                )
30                                select new { Type = animal, Sound = sound };
31 
32         foreach (var animal in organizedAnimals)
33         {
34             Console.WriteLine($"{animal.Type.ToString()} - {animal.Sound}");
35         }
36 
37         foreach (var a in animals)
38         {
39             if (a is Cat { Name is var name }) //類型及屬性匹配,is表達式
40             {
41                 Console.WriteLine($"Name of {nameof(Cat)} is {name}");
42             }
43 
44             string sound = "";
45             switch (a) //匹配switch語句
46             {
47                 case Dog d when d.Name == "hola":
48                     sound = "woof... hola" + d.BarkLikeCrazy();
49                     break;
50                 case Dog d:
51                     sound = "woof..." + d.BarkLikeCrazy();
52                     break;
53                 case Cat c:
54                     sound = "meow";
55                     break;
56                 case IEnumerable<Animal> l when l.Any():
57                     //TODO: any logic;
58                     break;
59                 case null:
60                     sound = "no animal";
61                     break;
62                 default:
63                     sound = "I'm mute..";
64                     break;
65             }
66             Console.WriteLine($"{a.ToString()} - {sound}");
67         }
68     }
69 }

  

註1:模式匹配的部分高級feature,已經確認在C#7.0中移除,可能出現在後續C#版本中。(#10888)。

註2:目前(2016-06-15VS15的最新Preview下,模式匹配的部分語法依然無法使用。

註3:由於目前仍然未在Roslyn中Release,後期有變動的可能,本文中涉及的樣例代碼以Mads Torgersen在#Build 2016上的演示的語法為準,本文涉及的案例有可能無法在VS15 RTM後正常使用,僅供參考。

  (當然,如果筆者樂意,會及時把後期得到確認的變更更新到本文中 ^_^!)

 

本文鏈接:http://www.cnblogs.com/ylvict/p/5588613.html (轉載請註明)

目前(2016年6月)C#7.0還未正式發佈,大家如果想體驗部分特性,可以去下載VS15預覽版,最終發佈的語法可能和本文中提及的有所不同,最新動態請大家關註Roslyn項目。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • ...
  • 前天去面試,讓我說下生命周期,本來之前就瞭解過,但是沒說出來,被深深的鄙視了;今天弄了一上午,現在發到這分享一下,有什麼錯誤請各位大牛們指出~~ 昨天面試,又遇到這問題了... 然後說了半天,人家問我一用戶控制項的周期在哪執行,我想了半天,也沒有想出來,回來只好再研究了.. 請求的本頁面Page-Lo ...
  • ...
  • FileAccess Enumeration 定義用於文件讀取、寫入訪問許可權的常數。此枚舉有一個FlagsAttribute特性,通過該特性可使其成員值按位組合。(命名空間:System.IO) 語法 [SerializableAttribute] [FlagsAttribute] [ComVisi... ...
  • 今天遇到了一個關於日期的問題,需要將2016-6-15 20:23:23這種形式的時間字元串轉換為2016年6月15日,由於學習經驗少,但是懵逼了0.0, 後來百度找到了相關方法。同時,也將常用的日期轉換方法的用法保存下來。供大家學習查閱。 我的代碼: 運行結果: ...
  • Private Sub textbox1_KeyPress(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles textbox1.KeyPress If e.KeyChar ...
  • 1、設置父窗體: 如果要將某個窗體設置為父窗體,只需將該窗體的IsMdiContainer屬性設置為True即可。 2、設置子窗體: 通過設為某個窗體的MdiParent屬性來確定該窗體是那個窗體的子窗體。 語法如下: 3、排列MDI子窗體: 語法如下: value:是MdiLayout的枚舉值之一 ...
  • 問題:如下代碼 想獲取某兩個Decimal類型數之間的商的大小,結果偶爾出錯(請註意是 偶爾) Decima t1; Decima t2; int shang =Convert.ToInt32(t1 / t2) ; 解決方法:將Decimal類型數據強制轉換成INT整型時 會有四捨五入的過程。如下, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...