簡介
模式匹配是 C# 7.0 開始引入的革命性特性,它提供了更簡潔、更強大的方式來檢查和提取數據中的信息。隨着每個版本的更新,模式匹配功能不斷強化,成為現代 C# 開發的核心特性。
模式匹配允許將輸入表達式與各種特徵進行匹配,支持多種模式類型。它主要用於:
is表達式:檢查並可能聲明變量。switch語句:傳統分支邏輯。switch表達式:更簡潔的表達式形式(C# 8.0引入)。
模式匹配演進歷程
| 版本 | 新增特性 |
|---|---|
| C# 7.0 | 基本模式匹配:is 表達式、switch 語句增強 |
| C# 8.0 | 遞歸模式、屬性模式、位置模式、switch 表達式 |
| C# 9.0 | 類型模式簡化、邏輯模式(and/or/not)、關係模式 |
| C# 10.0 | 擴展屬性模式 |
| C# 11.0 | 列表模式、切片模式 |
基礎模式類型
聲明模式
// 檢查類型並聲明新變量
if (obj is string str)
{
Console.WriteLine($"字符串長度: {str.Length}");
}
// 傳統方式對比
if (obj is string)
{
string str = (string)obj;
Console.WriteLine($"字符串長度: {str.Length}");
}
類型模式
// 只檢查類型,不聲明變量
if (obj is string)
{
Console.WriteLine("這是一個字符串");
}
// 在 switch 表達式中使用
var result = obj switch
{
string => "它是字符串",
int => "它是整數",
_ => "其他類型"
};
常量模式
// 檢查特定值
if (value is 5) { /* 值等於5 */ }
if (value is null) { /* 值為null */ }
if (value is "hello") { /* 字符串比較 */ }
// 在 switch 中
string message = value switch
{
0 => "零",
1 => "一",
null => "空值",
_ => "其他值"
};
高級模式匹配
屬性模式
// 檢查對象屬性
if (person is { Name: "John", Age: > 18 })
{
Console.WriteLine("John 已成年");
}
// 嵌套屬性模式
if (order is { Customer: { Address: { City: "Beijing" } } })
{
Console.WriteLine("北京客户的訂單");
}
// C# 10 擴展屬性模式
if (order is { Customer.Address.City: "Beijing" })
{
Console.WriteLine("北京客户的訂單(簡化寫法)");
}
位置模式(元組模式)
// 元組解構和匹配
var point = (x: 5, y: 10);
var quadrant = point switch
{
(0, 0) => "原點",
(var x, var y) when x > 0 && y > 0 => "第一象限",
(var x, var y) when x < 0 && y > 0 => "第二象限",
(var x, var y) when x < 0 && y < 0 => "第三象限",
(var x, var y) when x > 0 && y < 0 => "第四象限",
_ => "在座標軸上"
};
邏輯模式(C# 9.0+)
// 使用邏輯運算符組合模式
bool IsValid(object obj) => obj is not null and (string or int);
// 複雜邏輯組合
var category = value switch
{
> 0 and < 10 => "小的正數",
< 0 or > 100 => "超出範圍",
not null => "非空值",
_ => "其他"
};
關係模式(C# 9.0+)
// 使用關係運算符
string GetSize(int value) => value switch
{
< 0 => "負數",
>= 0 and < 10 => "小",
>= 10 and < 100 => "中",
>= 100 => "大"
};
// 與類型模式結合
string Describe(object obj) => obj switch
{
int i when i < 0 => "負整數",
int i when i > 0 => "正整數",
int => "零",
_ => "其他"
};
列表模式(C# 11.0+)
// 匹配數組或列表的特定模式
int[] numbers = { 1, 2, 3, 4 };
var result = numbers switch
{
[1, 2, 3, 4] => "精確匹配",
[1, 2, ..] => "以1,2開頭",
[.., 3, 4] => "以3,4結尾",
[1, .. var middle, 4] => $"以1開頭4結尾,中間有{middle.Length}個元素",
[] => "空數組",
_ => "其他模式"
};
// 切片模式
if (numbers is [var first, .. var rest])
{
Console.WriteLine($"第一個元素: {first}, 剩餘元素: {rest.Length}");
}
字符串模式
string text = "Hello, World";
if (text is ['H','e','l','l','o', ..])
{
Console.WriteLine("以Hello開頭");
}
// 與Span<char>模式匹配結合
ReadOnlySpan<char> span = text.AsSpan();
if (span is ['H','e','l','l','o', ..])
{
Console.WriteLine("匹配Span");
}
自定義模式匹配
// 通過 Deconstruct 方法支持位置模式
public class Point
{
public int X { get; }
public int Y { get; }
public void Deconstruct(out int x, out int y)
{
x = X;
y = Y;
}
}
// 現在可以對 Point 使用位置模式
var quadrant = point switch
{
(0, 0) => "原點",
(var x, var y) when x > 0 && y > 0 => "第一象限",
// ...
};w
表達式樹中的模式匹配
Expression<Func<object, bool>> expr = o => o switch
{
int i when i > 0 => true,
string s when s.Length > 5 => true,
_ => false
};
// 解析表達式樹
if (expr.Body is SwitchExpression switchExpr)
{
foreach (SwitchCase @case in switchExpr.Cases)
{
// 處理每個case
}
}
實際應用場景
數據驗證和處理
public ValidationResult Validate(Order order)
{
return order switch
{
null => ValidationResult.Failure("訂單不能為空"),
{ TotalAmount: <= 0 } => ValidationResult.Failure("金額必須大於0"),
{ Customer: null } => ValidationResult.Failure("客户信息缺失"),
{ Items: [] } => ValidationResult.Failure("訂單項不能為空"),
{ Status: OrderStatus.Cancelled } => ValidationResult.Failure("訂單已取消"),
_ => ValidationResult.Success()
};
}
API 響應處理
public string HandleResponse(ApiResponse response)
{
return response switch
{
{ StatusCode: 200, Data: not null } => "成功",
{ StatusCode: 404 } => "資源未找到",
{ StatusCode: >= 400 and < 500 } => "客户端錯誤",
{ StatusCode: >= 500 } => "服務器錯誤",
{ Error: not null } => $"錯誤: {response.Error.Message}",
_ => "未知響應"
};
}