日韩欧美人妻无码精品白浆,夜夜嗨AV免费入口,国产欧美官网在线看,高校回应聋哑女生因长相完美被质疑

LOGO OA教程 ERP教程 模切知識(shí)交流 PMS教程 CRM教程 開發(fā)文檔 其他文檔  
 
網(wǎng)站管理員

C# 模式匹配全解:原理、用法與易錯(cuò)點(diǎn)

freeflydom
2025年6月9日 9:15 本文熱度 41

引言

隨著C#不斷發(fā)展,"模式匹配"(Pattern Matching)已經(jīng)成為讓代碼更加友好、可讀和強(qiáng)大的核心特性。從 C# 7.0 初次引入,到 C# 11的能力擴(kuò)展,模式匹配為處理類型判斷、屬性解構(gòu)、集合匹配等提供了簡(jiǎn)潔、高效且類型安全的表達(dá)方式。它不僅能讓 if/switch 等控制結(jié)構(gòu)變得“聲明式”,還能帶來(lái)性能提升。在這篇文章里,我們將深入剖析 C 的所有模式匹配語(yǔ)法和用法,追蹤其演變,講清一些容易混淆和誤用的地方,讓大家能了解模式匹配本質(zhì)。


1. 什么是模式匹配

模式匹配本質(zhì)上是一種表達(dá)式判定工具:用以檢查一個(gè)對(duì)象是否與某種“模式”相吻合,如果吻合,還允許對(duì)其分解、綁定成員變量。這可以是類型檢查、常量判斷、屬性結(jié)構(gòu)匹配等。

傳統(tǒng)C#寫法:

if (person != null && person.Age >= 18 && person is Employee
    && ((Employee)person).YearsAtCompany > 5) {
    // 處理邏輯
}

模式匹配寫法:

if (person is Employee { Age: >= 18, YearsAtCompany: > 5 }) {
    // 處理邏輯
}

更簡(jiǎn)潔、可讀、類型安全,不需要重復(fù)顯式強(qiáng)制轉(zhuǎn)型。


2. C#7.0 初代模式匹配特性

2.1 Null 模式與常量模式

C#7.0 首先支持了用is直接與null以及常量對(duì)比:

if (obj is null) Console.WriteLine("對(duì)象為null");
if (d is Math.PI) Console.WriteLine("d 是圓周率");
if (str is "test") Console.WriteLine("str內(nèi)容等于test");

注意:常量匹配僅支持編譯期常量,比如數(shù)字、字符串、bool、enum、const字段和null。不能直接用非const變量或表達(dá)式。

這個(gè)限制為何存在?

  • 編譯器要保證 switch 和 if 全覆蓋檢查,如果允許變量參與,則難推導(dǎo) exhaustiveness(全覆蓋)。
  • 也可避免不可預(yù)期的副作用與邏輯混亂(比如變量運(yùn)行期改變等)。

2.2 類型模式與變量捕獲

類型模式允許 you not only 判斷類型,還能直接捕獲變量:

if (shape is Circle circle1) 
    Console.WriteLine($"圓的半徑為 {circle1.Radius}");

甚至可以鏈?zhǔn)脚袛啵?/p>

if (shape is Rectangle r && r.Width == r.Height)
    Console.WriteLine("正方形");

非常適用于臨時(shí)變量創(chuàng)建、減少?gòu)?qiáng)制類型轉(zhuǎn)換(顯式as/cast)代碼雜音。

is vs as?

  • is 結(jié)合新模式后可以直接安全聲明變量,無(wú)需后續(xù) null 檢查。
  • as 后還得寫 if (x != null)。

2.3 Discard 與 var 模式

  • Discard(_):匹配但忽略,用于 switch 的 default 分支或類型“只是判斷,不關(guān)心值”。
  • var:總是匹配成功,并引出變量。通常用于解構(gòu)場(chǎng)景,比如 switch/case 匹配對(duì)象成員。
if (obj is var o)
   Console.WriteLine(o); // 不管 obj 是否為null,o 指向原始值(即使null)

?? 這里容易誤用!

不要用 var 跳過(guò) null 檢查。因?yàn)檫@樣會(huì)把 null 值“吞掉”,造成 NullReferenceError 隱患。

if (p is var _)  
{             // 這里仍可能是 null  
    Console.WriteLine(p.Length); // NullReferenceException  
}  

2.4 switch 語(yǔ)句的模式匹配

傳統(tǒng) switch 只能匹配簡(jiǎn)單的枚舉或數(shù)字等,C#7.0 后支持以下寫法:

switch (seq) {
    case Array a: return a.Length;
    case ICollection<T> c: return c.Count;
    case IEnumerable<T> _: return seq.Count();
    default: return 0;
}
  • 某類型滿足條件即分支命中
  • Discard case IEnumerable<T> _:
  • default處理剩余情況

switch 的 when 子句

when 只能用于 switch:

case Array a when a.Length < 10: return a.Length;

無(wú)法用于 if!


3. C#8.0: Switch表達(dá)式、屬性、位置、元組模式

3.1 表達(dá)式 Switch

C#8 引入 switch-表達(dá)式,極大提升 switch 可讀性和函數(shù)式編程體驗(yàn):

string whatShape = shape switch {
    Circle c     => $"circle radius: {c.Radius}",
    Rectangle _  => "rectangle",
    _            => "null or unknown"
};
  • 匹配分支是表達(dá)式,不能有多條語(yǔ)句

=>右邊直接返回值,非常適合表達(dá)式體成員:

public static string Describe(this Shape s) => s switch { ... };

3.2 屬性模式 (Property Patterns)

可直接針對(duì)屬性表達(dá)式判定

if (shape is Circle { Radius: 1.0 })
    Console.WriteLine("單位圓");
whatShape = shape switch {
    Rectangle { Width: 10, Height: 5 } => "10x5 矩形",
    Rectangle { Width: var x, Height: var y } => $"rect: {x}x{y}",
    { } => "非null",
    _ => "null"
};

重點(diǎn)說(shuō)明:

  • { } 代表對(duì)象非null。
  • { Width: 10, Height: 5 } 同時(shí)要求2個(gè)屬性等于指定值。
  • { Width: var x, Height: >5 } 可以對(duì)屬性用關(guān)系操作和抽取變量。
  • 若對(duì)象有Deconstruct方法,可用位置/元組模式更優(yōu)雅。

3.3 位置模式(Positional Patterns)

利用 Deconstruct 抽取變量:

public void Deconstruct(out double w, out double h) => (w, h) = (Width, Height);
shape switch {
    Rectangle(var x, var y) => $"矩形尺寸:{x}x{y}",
    ...
}
  • 用于解構(gòu)類對(duì)象(類似元組)
  • 寫法類似解構(gòu)元組

3.4 元組模式

處理多個(gè)參數(shù)的模式組合:

(c1, c2, c3) switch {
    (Color.Blue, Color.White, Color.Red) => "France",
    (Color.Green, Color.White, Color.Red) => "Italy",
    _ => "Unknown"
};
  • 有效解決“復(fù)雜組合條件冗長(zhǎng)”的老大難。
  • 更直觀表達(dá)多變量匹配,不需層層嵌套。

4. C#9.0: 組合、括號(hào)及關(guān)系模式

4.1 組合模式(and/or/not)

組合條件極其強(qiáng)大:

c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z') or '.' or ','

等價(jià)于:

(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '.' || c == ','

not 語(yǔ)法

if (obj is not null) { ... }

比傳統(tǒng) !(obj is null) 更直觀。

4.2 關(guān)系模式(Relational Patterns)

直接用 >, <, >=, <= 表達(dá)區(qū)間

rate = monthlyIncome switch {
    >=0 and <1000 => 0,
    <5000 => 10,
    _ => 20
};

結(jié)合屬性/類型模式:

shape switch {
    Circle { Radius: >1 and <=10 } => "較合理圓",
    Circle { Radius: >10 } => "過(guò)大圓",
    Rectangle => "矩形",
    _ => "不匹配"
};

4.3 類型模式精簡(jiǎn)

C#9 類型模式無(wú)需 underscore,eg:Rectangle 直接寫。


5. C#10.0: 擴(kuò)展屬性模式

支持嵌套點(diǎn)表達(dá)式:

之前版本:

x is Person { FirstName: { Length: <=5 } }

C#10:

x is Person { FirstName.Length: <=5 }

讓屬性鏈判定更加直觀簡(jiǎn)潔。


6. C#11.0: 列表與切片模式

6.1 列表模式

讓數(shù)組/集合結(jié)構(gòu)模式判定成為可能:

if (arr is [1, 2, 3])
// 匹配長(zhǎng)度為3,內(nèi)容依次為1,2,3
  • [..]: 切片模式,等價(jià)于“0個(gè)或多個(gè)元素”
  • _: 忽略一個(gè)元素(discard)
[_, >0, ..]      // 至少2個(gè)元素,第二個(gè)>0
[.., <=0, _]     // 至少2個(gè)元素,倒數(shù)第二個(gè)<=0且不關(guān)心最后一個(gè)

注意:切片只能出現(xiàn)一次。

6.2 列表遞歸

可以做嵌套匹配:

bool EndsWithSingleIntList(List<List<int>> lists) => lists is [.., [_]];
// 至少一個(gè)元素,且最后一個(gè)是單元素list

6.3 支持的結(jié)構(gòu)

只要類型有 Length/Count 屬性和支持 [index] 則可用列表模式,如 string、數(shù)組、自定義集合(只需這兩個(gè)成員)。

例如處理國(guó)別碼:

switch (s) {
    case [char c0, char c1]: // 即 s.Length==2
        ...
}

7. 模式匹配背后的實(shí)現(xiàn)與性能分析

7.1 不是“魔法”,而是IL優(yōu)化

許多人以為 pattern matching 是一種基于反射或者表達(dá)式樹的黑魔法。實(shí)際上,編譯器常常能把很多 pattern 匹配轉(zhuǎn)為高效的“順序判斷”或“跳表”等機(jī)器碼。

例如:

c is (>= 'a' and <= 'z') or (>= 'A' and <= 'Z') or '.' or ','

編譯后 Equals:

(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '.' || c == ','

對(duì)于一組常量匹配:

statusCode is 0x1000 or 0x1001 or 0x1002 or 0x2000 or 0x2001 or 0x3000

編譯器會(huì)變換成:

return ((uint)(statusCode - 4096) <= 2u || (uint)(statusCode - 8192) <= 1u || statusCode == 12288);

即用范圍短路、減少 equals 判斷次數(shù)。

?? 建議:

對(duì)于性能敏感代碼,請(qǐng)結(jié)合 Benchmark.NET 做實(shí)測(cè)對(duì)比。有時(shí)手寫的判定和 pattern matching 效果類似,甚至后者更優(yōu)。


8. 常見(jiàn)誤區(qū)與最佳實(shí)踐

8.1 不要用 pattern 替代多態(tài)

最容易見(jiàn)的誤用是用模式匹配處理繼承結(jié)構(gòu)的多態(tài)行為:

// xxx
public static double Area(this Shape shape) => shape switch {
    Circle c    => c.Radius * c.Radius * Math.PI,
    Rectangle r => r.Width * r.Height
};

事實(shí)上,應(yīng)該優(yōu)先用抽象基類/接口的虛方法或?qū)傩?/strong>:

abstract class Shape { public abstract double Area {get;} }
class Circle : Shape {
    public double Radius { get; set; }
    public override double Area => Radius * Radius * Math.PI;
}

為什么?

  • 可擴(kuò)展性強(qiáng)(新子類無(wú)需修改 Area 邏輯,符合開閉原則)。
  • 虛調(diào)用比類型判定快。
  • 更少維護(hù)負(fù)擔(dān)。

8.2 Constant-Only 限制

只有編譯期常量才能用于模式匹配,如果需要支持運(yùn)行時(shí)變量,需采用傳統(tǒng)判定。

8.3 避免濫用 var/discard

  • 不要用 is var x 跳過(guò) null 檢查。
  • discard _ 只適合確實(shí)不關(guān)心值的場(chǎng)景,用后不要嘗試訪問(wèn)。

8.4 List/Slice 模式性能

使用 [..var arr, x] 這種 slice+變量捕獲,編譯器可能分配新數(shù)組,造成性能下降。大數(shù)據(jù)集合應(yīng)謹(jǐn)慎。


9. 小結(jié)與展望

Pattern Matching 是現(xiàn)代 C# 代碼的“瑞士軍刀”,能極大提升 if/else、switch/case 類代碼的簡(jiǎn)潔性、表達(dá)力和類型安全性,在 switch 表達(dá)式等場(chǎng)景下優(yōu)勢(shì)更加明顯。它不僅代碼層面更美觀,也能為某些條件分支提供更優(yōu)指令級(jí)性能。然而,模式匹配并非多態(tài)(polymorphism)、虛方法的替代品!業(yè)務(wù)邏輯與類型分發(fā)仍建議用面向?qū)ο笤瓌t解決。

?轉(zhuǎn)自https://www.cnblogs.com/InCerry/p/-/introduce-cs-pattern-match


該文章在 2025/6/9 9:15:57 編輯過(guò)
關(guān)鍵字查詢
相關(guān)文章
正在查詢...
點(diǎn)晴ERP是一款針對(duì)中小制造業(yè)的專業(yè)生產(chǎn)管理軟件系統(tǒng),系統(tǒng)成熟度和易用性得到了國(guó)內(nèi)大量中小企業(yè)的青睞。
點(diǎn)晴PMS碼頭管理系統(tǒng)主要針對(duì)港口碼頭集裝箱與散貨日常運(yùn)作、調(diào)度、堆場(chǎng)、車隊(duì)、財(cái)務(wù)費(fèi)用、相關(guān)報(bào)表等業(yè)務(wù)管理,結(jié)合碼頭的業(yè)務(wù)特點(diǎn),圍繞調(diào)度、堆場(chǎng)作業(yè)而開發(fā)的。集技術(shù)的先進(jìn)性、管理的有效性于一體,是物流碼頭及其他港口類企業(yè)的高效ERP管理信息系統(tǒng)。
點(diǎn)晴WMS倉(cāng)儲(chǔ)管理系統(tǒng)提供了貨物產(chǎn)品管理,銷售管理,采購(gòu)管理,倉(cāng)儲(chǔ)管理,倉(cāng)庫(kù)管理,保質(zhì)期管理,貨位管理,庫(kù)位管理,生產(chǎn)管理,WMS管理系統(tǒng),標(biāo)簽打印,條形碼,二維碼管理,批號(hào)管理軟件。
點(diǎn)晴免費(fèi)OA是一款軟件和通用服務(wù)都免費(fèi),不限功能、不限時(shí)間、不限用戶的免費(fèi)OA協(xié)同辦公管理系統(tǒng)。
Copyright 2010-2025 ClickSun All Rights Reserved