博客 / 詳情

返回

告別 if-else:C#.NET 模式匹配讓代碼更優雅的正確方式

簡介

模式匹配是 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}",
        _ => "未知響應"
    };
}
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.