您的位置:首頁 > 軟件教程 > 教程 > C#.Net筑基-模式匹配匯總

C#.Net筑基-模式匹配匯總

來源:好特整理 | 時間:2024-05-14 09:46:21 | 閱讀:94 |  標(biāo)簽: 匹配 T Net C   | 分享到:

從C#7開始支持的 模式匹配 語法(糖,挺甜),可非常靈活的對數(shù)據(jù)進(jìn)行條件匹配和提取,經(jīng)過多個版本的完善,已經(jīng)非常強(qiáng)大了。

C#.Net筑基-模式匹配匯總

01、模式匹配概述

C#7 開始支持的 模式匹配 語法(糖,挺甜),可非常靈活的對數(shù)據(jù)進(jìn)行條件匹配和提取,經(jīng)過多個版本的完善,已經(jīng)非常強(qiáng)大了。

C# 支持多種模式,包括聲明、類型、常量、關(guān)系、屬性、列表、var 和棄元等,在 is 、 switch 語句、 switch 表達(dá)式中使用,還可以使用布爾邏輯關(guān)鍵字 and 、 or not 組合多個模式,極大的簡化了代碼編寫,可讀性也還不錯。

標(biāo)題 說明 示例/備注
類型和聲明模式 如果類型兼容,則申明并賦值變量 if (age is int i)
常量模式 檢查表達(dá)式值是否等于、不等于(not)常量值 if(age is null || age is 0)
關(guān)系模式 >< 使用關(guān)系運(yùn)算符 < 、 > 、 <= >= 匹配 case 0 or <=6
邏輯模式 not > and > or 連接多個模式表達(dá)式 case < 12 and ( >6 or 6)
屬性模式 {:} 對實(shí)例的屬性、字段進(jìn)行模式匹配: {屬性/字段:匹配模式} if (b is { Year: < 2000, Month: 1 or 11 })
位置模式(解構(gòu)) 基于解構(gòu)賦值進(jìn)行模式匹配: (解構(gòu)參數(shù)) if(point is (_,>0,>0))
var 模式 var 申明(捕獲)任意局部變量 if(point is var p && p.X>0)
棄元模式_ 棄元模式 _ 來匹配任何(其他)表達(dá)式 表示不要的
列表模式[] 對數(shù)組(列表)進(jìn)行匹配,在中括號 [] 中匹配列表中的項(xiàng) if(numbers is [_, 2, 3, ..])

C#.Net筑基-模式匹配匯總

? 模式匹配基本都是語法糖,味道都不錯!C#在編譯時會輸出原本的基礎(chǔ)代碼,可通過 https://sharplab.io/ 在線查看編譯后的代碼。


02、模式匹配

2.1、類型和聲明模式

檢查類型是否匹配,同時申明變量,如果類型兼容則申明并賦值變量,該變量在后面代碼作用域中有效。

object age = "123";
if (age is int i)  //類型匹配+申明變量i
{
    Console.WriteLine($"age1 = {i}");
}
switch (age)
{
    case string:   //類型匹配
        Console.WriteLine($"type is string");
        break;
    case int iage: //類型匹配+申明變量iage
        Console.WriteLine($"age2 = {iage}");
        break;
}

//上面is語句編譯后的代碼效果:
if (obj is int)
{
    int value = (int)obj;
}

2.2、常量模式

檢查表達(dá)式值是否等于、不等于( not )常量值,常量值包括字面量常量,也包括 const 常量值。傳統(tǒng)的 Switch 語句就是常量模式匹配。

object age = null;
if (age is not null  && age is 100)   //age is 100 等同于 age is int && (int)age==100
{
    Console.WriteLine($"age1 = {age}");
}
var type = age switch{
        1 or 2 or 3=>"嬰兒",
        4 => "幼兒",
        null or not 5 => "unknow",
        _=>"",
};

2.3、關(guān)系模式 ><

用關(guān)系運(yùn)算符來匹配表達(dá)式,就是對常量數(shù)值進(jìn)行大小比較運(yùn)算,使用關(guān)系運(yùn)算符 < 、 > 、 <= >= ,多個表達(dá)式可用 and 、 or 連接,當(dāng)然也支持括號。

object age = 6;
if (age is int n and >= 6)
{
    Console.WriteLine("666");
}
switch (age)
{
    case 0 or <=6:
        Console.WriteLine("幼兒");
        break;
    case < 12 and ( >6 or 6):
        Console.WriteLine("青少年");
        break;
}

2.4、邏輯模式 not / and / or

not and or 模式連結(jié)符來創(chuàng)建邏輯模式,連接多個模式表達(dá)式。

  • 優(yōu)先級順序: not > and > or 。
  • 推薦使用 (括號) 顯示控制優(yōu)先順序,可讀性更好。
object age = 6;
if (age is int n and (not 6 or >5) )
{
    Console.WriteLine("666");
}

2.5、屬性模式 {:}

對實(shí)例的屬性、字段進(jìn)行模式匹配,可以嵌套其他模式匹配,非常的強(qiáng)大,屬性匹配用大括號來包裝 {屬性/字段:匹配模式} 。

  • 多個屬性/字段都匹配為 true 時,最終才會匹配成功。
  • 可以結(jié)合類型申明模式使用。
  • 可嵌套使用,會遞歸匹配。
DateTime birthday = new DateTime(1999, 11, 12);
if (birthday is { Year: < 2000, Month: 1 or 11 })
{
    Console.WriteLine("年齡、星座不合適");
}

//嵌套使用
public record Point(int X, int Y);
public record Segment(Point Start, Point End);

static bool IsAnyEndOnXAxis(Segment segment) =>
    segment is { Start: { Y: 0 } } or { End: { Y: 0 } };
static bool IsAnyEndOnXAxis(Segment segment) =>
    segment is { Start.Y: 0 } or { End.Y: 0 };

2.6、位置模式(解構(gòu))

基于解構(gòu)賦值進(jìn)行模式匹配:

  • Tuple 、 record 和 DictionaryEntry 是內(nèi)置支持解構(gòu)的,關(guān)于解構(gòu)賦值可參考相關(guān)內(nèi)容。
  • 用括號 () 報(bào)裝,這也是 解構(gòu)(Deconstruct) 的語法形式。
  • 可以嵌套其他模式匹配,如常量、關(guān)系、邏輯、屬性模式等。
void Main()
{
	Point point = new Point("sam", 12, 13);
	var len = point switch
	{
		//類型匹配、屬性模式、位置模式:Name屬性必須為string,且長度為0,X、Y值為0
		(string { Length: <= 0 }, 0, 0) => 0,		
		(_, > 0, 0) => point.X,  //X值大于0,Y值為0
		(_, 0, > 0) => point.Y,  //Y值大于0,X值為0
		(_, 10 or > 10, 10 or > 10) p => p.X * p.Y,
		_ => 0,
	};
}
public record Point(string Name, int X, int Y);

2.7、var 模式

var 申明(捕獲)任意局部變量,把表達(dá)式的結(jié)果分配給 var 臨時變量。算是類型模式的變種,將類型名替換成了 var 。

void Main()
{
	Point point = new Point("sam", 12, 13);
	if(point is var p && p.X>0 && p.Y>0){   //is var
		Console.WriteLine("OK");
	}	
	var len = point switch
	{
		var (_,x,y) when x>0 && y>0 => true,// var
	};
}
public record Point(string Name, int X, int Y);

2.8、棄元模式_

棄元模式 (Discard Pattern),字面理解就是被遺棄、沒人要的?梢詫壴J娇醋鍪且粋占位符,表示一個沒人用的變量,可匹配任意類型,用來 簡化代碼 。語法是用下劃線“ _ ”表示。

常用場景

  • 1、解構(gòu)時的占位符。
  • 2、在 Switch 中匹配任意其他模式,類似 default 的作用。
  • 3、在 out 參數(shù)中占位,表示一個沒人用的 out 參數(shù)。
  • 4、獨(dú)立棄元,接收無用的表達(dá)式輸出。
var tuple = new Tuple(3, 4);
var (x, _) = tuple;   //1、只需要第一個參數(shù),其他就用“_”來占位
Console.WriteLine(x); //3

_= x switch
{
    2 or <2 => "small",
    int and <18=>"young",
    _=>"other",  //2、匹配其他模式,效果同default
};

int.TryParse("", out _); //3、不用的out變量,實(shí)際上是申明了變量的

async void Print(object arg)
{
    _ = arg ?? throw new ArgumentException();  //4、接收無用的返回,效果同下
    if (arg == null) throw new ArgumentException();
    _ = Task.Run(()=>Console.WriteLine("task run")); //接收一個不用的返回
}

棄元模式 _ 是一個提供給編譯器用的符號,告訴編譯這個變量不用了,編譯器會根據(jù)情況進(jìn)行優(yōu)化處理。在對 out 參數(shù)使用時,編譯器會自動創(chuàng)建變量,如下代碼:

int.TryParse("",out _);
//實(shí)際編譯后的代碼如下
int result;
int.TryParse("", out result);

C#.Net筑基-模式匹配匯總

?需要注意的是 下劃線 _ 是并不是一個關(guān)鍵字,也能當(dāng)做參數(shù)名來使用,不要混用。

2.9、列表模式[]

C#11支持的,對數(shù)組(列表)進(jìn)行匹配,在中括號 [] 中匹配列表中的項(xiàng)。

  • 跳過的項(xiàng)可以用棄元模式 _ 。
  • 可以用數(shù)組的切片模式匹配開頭、結(jié)尾的元素。
void Main()
{
	int[] numbers = { 1, 2, 3, 4 };

	Console.WriteLine(numbers is [_, 2, 3, ..]);        // True
	Console.WriteLine(numbers is [0 or 1, <= 2, >= 3]); // False
}

03、模式匹配應(yīng)用

上面的各種模式匹配主要就用在 is 運(yùn)算符 、 switch 語句 、 switch 表達(dá)式 中。

C#.Net筑基-模式匹配匯總

3.1、is運(yùn)算符

is 運(yùn)算符 本來主要是用來檢測類型兼容性的,加上模式匹配就能玩出各種花樣了,極大簡化了讓各種檢查類的代碼。

object value = 12;
if (value is int && value is not null) //is類型檢測+邏輯模式
{            
    Console.WriteLine(value);
}
if (value is int a && a > 6) //+申明模式
{
    Console.WriteLine(a);
}
if (value is int age and > 10 and < 14) //關(guān)系模式
{
    Console.WriteLine(age);
}
var user = new { Name = "sam", Age = 12 };
if (user is { Name: _, Age: > 10 })    //屬性模式
{
    Console.WriteLine(user.Name);
}
int[] arr = new int[] { 1, 2, 3 };
if (arr is [> 0, ..])  //列表模式:第一個元素>0
{
    Console.WriteLine(arr);
}
var dt = new Tuple("sam", 100);
if (dt is (_, > 60) d) //位置模式+申明模式(好像沒什么用)
{
    Console.WriteLine(d.Item1);
}

3.2、switch..case語句

switch..case 語句 是很多語言中都有的基本多條件分支語句,傳統(tǒng)的 case 只能用于匹配常量,多用于枚舉。

  • case 不能穿透,一個 case 執(zhí)行完后必須 break 結(jié)束,或者 return 返回(退出方法),可以多個 case 匹配執(zhí)行一組邏輯代碼。
  • 傳統(tǒng)的 case 就是常量模式,而現(xiàn)代的 case 可以結(jié)合上面多種模式使用,非常強(qiáng)大。
  • when ,自由附加更多條件。
	int age = 22;
	string sex = "Male";	
	switch (age)
	{
		case 1:
		case 2:
			Console.WriteLine("嬰兒");
			break;
		case <= 3:
			Console.WriteLine("幼兒");
			break;
		case > 10 and < 16:
			Console.WriteLine("青少年");
			break;
		case > 18 when sex == "Male":
			Console.WriteLine("成年男性");
			break;
		case int:
			break;
	}

3.3、switch表達(dá)式

C#8 switch 有了新的語法 —— switch 表達(dá)式 ,可以看做是 switch..case 語句的一個變種,使用比較類似。 switch 表達(dá)式是一個賦值(輸出)語句。

  • => 左側(cè)為模式(返回一個bool),如果模式匹配(true)則返回右側(cè)的值,最后一個棄元模式匹配其他情況,同 default 效果。
int type = 6;
var message = type switch
{
    <= 1 => "success",
    2 => "warning",
    3 => "error",
    > 3 and < 10 => "other error",
    _ => "unkonwn error",
};

可以用 when 來進(jìn)行更多的判斷, when 后面的表達(dá)式就很自由了,只要返回 boo 即可。

object type = 6;
var message = type switch
{
    int i when i<6 => "ok",
    string s when s=="null"=>"Null",
    string s when !string.IsNullOrEmpty(s)=>"string value",
    _=>"unknown value"
};
Console.WriteLine(message);

支持多個變量的組合模式:用括號 () 包含多個變量

string gender = "male";
int age = 10;
string type = (gender,age) switch{
    ("male",>18)=>"VIP",
    (not "male",>26 and <35)=>"VVIP",
    _=>"",
};

參考資料

  • 模式匹配 - 模式中的 is 和 switch 表達(dá)式,以及 and、or 和 not 運(yùn)算符
  • 析構(gòu)元組和其他類型

??版權(quán)申明 :版權(quán)所有@安木夕,本文內(nèi)容僅供學(xué)習(xí),歡迎指正、交流,轉(zhuǎn)載請注明出處! 原文編輯地址-語雀

小編推薦閱讀

好特網(wǎng)發(fā)布此文僅為傳遞信息,不代表好特網(wǎng)認(rèn)同期限觀點(diǎn)或證實(shí)其描述。

相關(guān)視頻攻略

更多

掃二維碼進(jìn)入好特網(wǎng)手機(jī)版本!

掃二維碼進(jìn)入好特網(wǎng)微信公眾號!

本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請發(fā)郵件[email protected]

湘ICP備2022002427號-10 湘公網(wǎng)安備:43070202000427號© 2013~2024 haote.com 好特網(wǎng)