在计算机编程里,条件判断是特别基础又重要的操作。咱们在处理复杂逻辑的时候,经常会碰到一堆嵌套的 if - else 或者 switch 语句,这代码写起来又长又乱,维护起来那叫一个头疼。不过呢,C# 里有个很厉害的模式匹配功能,它在新版本里又有了不少新语法,能帮咱们大大简化复杂的条件判断。下面咱们就来好好聊聊这个事儿。

一、模式匹配基础回顾

在深入了解进阶应用之前,咱们先简单回顾一下模式匹配的基础概念。模式匹配允许开发者使用一种更简洁、更具表现力的方式来检查值的结构,并根据不同的情况执行相应的操作。C# 从早期版本就开始支持模式匹配,最初主要用于 switch 语句。

简单示例:传统 switch 与模式匹配 switch 的对比

传统的 switch 语句:

// 技术栈:C#
// 定义一个颜色枚举
enum Color
{
    Red,
    Green,
    Blue
}

class Program
{
    static string DescribeColorTraditional(Color color)
    {
        switch (color)
        {
            case Color.Red:
                return "It's red!"; // 若颜色是红色,返回此描述
            case Color.Green:
                return "It's green!"; // 若颜色是绿色,返回此描述
            case Color.Blue:
                return "It's blue!"; // 若颜色是蓝色,返回此描述
            default:
                return "Unknown color"; // 若颜色不是上述三种,返回未知颜色描述
        }
    }
}

使用模式匹配的 switch 语句:

// 技术栈:C#
static string DescribeColorPatternMatching(Color color)
{
    return color switch
    {
        Color.Red => "It's red!", // 若颜色是红色,返回此描述
        Color.Green => "It's green!", // 若颜色是绿色,返回此描述
        Color.Blue => "It's blue!", // 若颜色是蓝色,返回此描述
        _ => "Unknown color" // 若颜色不是上述三种,返回未知颜色描述
    };
}

从这个例子可以看出,模式匹配的 switch 语句更加简洁明了,代码可读性更高。

二、新语法在模式匹配中的应用

1. 关系模式(Relational Patterns)

关系模式允许我们在模式匹配中使用比较运算符(如 <, <=, >, >=)。这在处理数值范围的判断时非常有用。

// 技术栈:C#
// 根据年龄判断所处年龄段
static string DescribeAge(int age)
{
    return age switch
    {
        < 0 => "Invalid age", // 年龄小于 0,为无效年龄
        < 18 => "Minor", // 年龄小于 18,是未成年人
        < 65 => "Adult", // 年龄小于 65 且大于等于 18,是成年人
        _ => "Senior" // 年龄大于等于 65,是老年人
    };
}

2. 逻辑模式(Logical Patterns)

逻辑模式包括 and, or, not 运算符,用于组合多个模式。

// 技术栈:C#
// 判断是否为工作日
static bool IsWeekday(DayOfWeek day)
{
    return day is not (DayOfWeek.Saturday or DayOfWeek.Sunday); 
    // 如果不是周六或周日,则为工作日
}

3. 切片模式(Slice Patterns)

切片模式可以帮助我们从数组或字符串中提取部分元素或字符。

// 技术栈:C#
static string GetInitials(string name)
{
    if (name.Length >= 2)
    {
        return $"{name[0]}{name[^1]}"; 
        // 取名字的第一个字符和最后一个字符作为缩写
    }
    return name;
}

三、应用场景分析

1. 数据验证

在数据验证的场景中,模式匹配可以让我们更清晰地定义数据的规则。

// 技术栈:C#
// 验证密码是否符合规则
static bool IsValidPassword(string password)
{
    return password is { Length: >= 8 } and (string s when s.Any(char.IsUpper) 
                                             && s.Any(char.IsLower) 
                                             && s.Any(char.IsDigit));
    // 密码长度至少为 8,且包含大写字母、小写字母和数字
}

2. 状态机实现

在实现状态机时,模式匹配可以让状态转换的逻辑更加清晰。

// 技术栈:C#
enum TrafficLightState
{
    Red,
    Yellow,
    Green
}

// 根据当前交通灯状态返回下一个状态
static TrafficLightState GetNextState(TrafficLightState currentState)
{
    return currentState switch
    {
        TrafficLightState.Red => TrafficLightState.Green, // 红灯之后是绿灯
        TrafficLightState.Yellow => TrafficLightState.Red, // 黄灯之后是红灯
        TrafficLightState.Green => TrafficLightState.Yellow, // 绿灯之后是黄灯
        _ => throw new ArgumentException("Invalid traffic light state")
    };
}

四、技术优缺点分析

优点

  • 代码简洁:模式匹配的新语法让代码更加简洁,减少了大量嵌套的 if - elseswitch 语句,提高了代码的可读性。
  • 表达力强:可以使用关系模式、逻辑模式等组合复杂的条件,更清晰地表达业务逻辑。
  • 易于维护:代码结构更清晰,修改和扩展逻辑时更加方便。

缺点

  • 学习成本:新语法对于初学者来说可能有一定的学习成本,需要花费时间来理解和掌握。
  • 性能开销:在某些复杂的模式匹配场景下,可能会有一定的性能开销,不过在大多数情况下这种开销是可以忽略不计的。

五、注意事项

1. 模式的顺序

在使用模式匹配时,模式的顺序非常重要。C# 会按照模式的顺序依次进行匹配,一旦找到匹配的模式就会停止匹配。因此,要确保将更具体的模式放在前面。

// 技术栈:C#
// 错误示例,可能无法正确匹配
static string MistakenPatternMatch(int num)
{
    return num switch
    {
        _ => "Default case", // 此模式会最先匹配所有情况,后面的模式无法执行
        1 => "One",
        2 => "Two"
    };
}

// 正确示例
static string CorrectPatternMatch(int num)
{
    return num switch
    {
        1 => "One", 
        2 => "Two",
        _ => "Default case" 
    };
}

2. 空引用检查

在模式匹配中,如果涉及到对象的属性或方法调用,要确保对象不为空,否则可能会引发 NullReferenceException

// 技术栈:C#
class Person
{
    public string Name { get; set; }
}

// 安全的模式匹配
static string GetPersonNameSafely(Person person)
{
    return person is { Name: string name } ? name : "Unknown"; 
    // 若 person 不为空且有 Name 属性,返回 Name,否则返回未知
}

文章总结

C# 的模式匹配新语法为我们简化复杂条件判断提供了强大的工具。通过关系模式、逻辑模式和切片模式等,我们可以更清晰、更简洁地表达业务逻辑。在数据验证、状态机实现等多种场景中,模式匹配都能发挥出色的作用。虽然它有一定的学习成本和性能开销,但总体来说利大于弊。在使用过程中,我们要注意模式的顺序和空引用检查等问题,以确保代码的正确性和健壮性。掌握好 C# 模式匹配的进阶用法,能让我们的代码开发更加高效、优雅。