• C#的Switch语句2(case后的值与模式匹配)


    switch语法结构

    基础的语法结构,在上一篇文章已经写了,具体请看:
    点击链接跳转

    case

    具体的值

    在上一篇文章提到过,Switch语句是一种选择结构,用于基于某个表达式的值来执行多个可能代码路径中的一个。这里的关键词是“离散值”,意味着Switch只能用于比较具体的、不可变的值,比如数字、枚举成员或者字符串(从C# 7.0开始支持)。它不适用于比较操作,比如大于、小于或等于这样的条件表达式。例如类似“如果速度大于60公里”的连续范围条件。但这个比较操作也不绝对,后面会讲解模式匹配,届时大家便会对这个比较操作有一个新看法。
    例如:

    switch (dayOfWeek)
    {
        case 1:
            Console.WriteLine("星期一");
            break;
        case 2:
            Console.WriteLine("星期二");
            break;
    }
    

    并且case标签后面要跟着一个常量表达式(const expression),这意味着它必须是一个在编译时就可以确定的值。这些值可以是整数、字符、枚举成员或者是字符串(从C# 7.0开始支持)。这里的“const”虽然没有直接体现在语法关键字上,但体现了case标签值需要具有静态确定性的原则。

    上面的示例中,1和2,就是常规的常量例子。

    枚举值

    枚举值也是常量表达式的一种,它们在编译时就已经确定:

        enum Color { Red, Green, Blue };
        static void Main()
        {
            Color favoriteColor = Color.Green;
    
            switch (favoriteColor)
            {
                case Color.Red:
                    Console.WriteLine("最喜欢的颜色是红色");
                    break;
                case Color.Green: // 枚举是一个const表达式
                    Console.WriteLine("最喜欢的颜色是绿色");
                    break;
                case Color.Blue:
                    Console.WriteLine("最喜欢的颜色是蓝色");
                    break;
            }
        }
    

    字符串

    从C# 7.0起,字符串也可以作为switch的表达式,同样遵循编译时常量的原则:

            string day = "Monday";
            switch (day)
            {
                case "Sunday":
                    Console.WriteLine("今天是星期日");
                    break;
                case "Monday": // 这是一个const表达式
                    Console.WriteLine("今天是星期一");
                    break;
                    // ...其他cases...
            }
    

    const关键字

    const关键字用于定义编译时常量,其值在编译期间就必须是已知的,并且之后不能更改。

    使用const定义case标签值的情况:

            const int OPTION_ONE = 1;
            const int OPTION_TWO = 2;
            const int OPTION_THREE = 3;
    
            int selection = OPTION_THREE;
            switch (selection)
            {
                case OPTION_ONE:
                    Console.WriteLine("选择了选项一");
                    break;
                case OPTION_TWO:
                    Console.WriteLine("选择了选项二");
                    break;
                case OPTION_THREE:
                    Console.WriteLine("选择了选项三");
                    break;
                default:
                    Console.WriteLine("无效的选择");
                    break;
            }
    

    在这个例子中,尽管使用了const关键字,但重要的是理解case标签后需要的是常量表达式这一特性,而非const关键字。

    如果没有匹配的值

    在Switch语句中,如果没有匹配的值要怎么办?这时候我们就需要使用default关键字了,default定义了一个默认的代码块,当Switch表达式的值与任何一个case标签的值都不匹配时,程序会执行default语句块中的代码。这在处理未预期或不明确的输入值时非常有用,确保了代码的健壮性,避免了因没有匹配的case而直接跳过Switch结构导致的潜在问题。

    default语句可以在Switch语句的任何位置出现,但通常推荐将其放在所有case之后,这样可以清晰地表明它是最后的兜底处理。

    延续之前的星期几示例,我们加入default语句处理无效的输入:

    int dayOfWeek = 8; // 故意设置一个无效的天数
    switch (dayOfWeek)
    {
        case 1:
            Console.WriteLine("星期一");
            break;
        case 2:
            Console.WriteLine("星期二");
            break;
        // ... 其他case省略 ...
        case 7:
            Console.WriteLine("星期日");
            break;
        default:
            Console.WriteLine("无效的天数输入");
            break;
    }
    

    在这个例子中,当dayOfWeek的值不是1到7之间的整数时,程序会执行default语句,打印出“无效的天数输入”。
    运行结果:
    在这里插入图片描述
    default语句是Switch语句的一个重要组成部分,它增强了代码的健壮性和灵活性。尽管在某些简单的场景下可能被忽略,但在开发高质量、容错性强的软件时,添加default分支是一个很好的编程习惯。最好在编写Switch语句时考虑所有可能的情况,并利用default来处理那些意外或未知的输入。

    default语句不一定要在最后

    default语句不强制要求必须放在Switch语句中所有case语句的最后。C#编译器允许程序员将default标签放置在Switch结构的任何位置。

    以下是一个例子:

    int option = 3;
    switch (option)
    {
        case 1:
            Console.WriteLine("Option 1 selected.");
            break;
        default: // 这里default不是在最后
            Console.WriteLine("Default case executed.");
            break;
        case 2:
            Console.WriteLine("Option 2 selected.");
            break;
        case 3:
            Console.WriteLine("Option 3 selected.");
            break;
    }
    

    运行结果:
    在这里插入图片描述

    尽管允许灵活放置default,但为了代码的可读性,推荐将default放在最后一个位置,作为所有其他case都不匹配时的最终处理逻辑。

    模式匹配

    前面提到过,从C# 7.0开始,switch语句支持模式匹配,这意味着你不仅可以比较变量的值,还可以直接解构对象或检查变量是否符合某种模式。这大大增强了switch的表达能力。

    class Program
    {
        // 定义形状基类
        public abstract class Shape
        {
        }
    
        // 定义圆形类
        public class Circle : Shape
        {
            public double Radius { get; set; }
    
            public Circle(double radius)
            {
                Radius = radius;
            }
        }
    
        // 定义正方形类
        public class Square : Shape
        {
            public double Side { get; set; }
    
            public Square(double side)
            {
                Side = side;
            }
        }
    
        // 定义矩形类
        public class Rectangle : Shape
        {
            public double Width { get; set; }
            public double Height { get; set; }
    
            public Rectangle(double width, double height)
            {
                Width = width;
                Height = height;
            }
        }
        static void Main()
        {
            var shape = GetShape();
            switch (shape)
            {
                case Circle c when c.Radius > 10:
                    Console.WriteLine($"大圆,半径为 {c.Radius}");
                    break;
                case Square s when s.Side > 10:
                    Console.WriteLine($"大方形,边长为{s.Side}");
                    break;
                case Rectangle r:
                    Console.WriteLine($"矩形,宽度为 {r.Width} 高度为 {r.Height}");
                    break;
                case null:
                    Console.WriteLine("Shape 为空");
                    break;
                default:
                    Console.WriteLine("未知形状");
                    break;
            }
        }
        // 获取随机形状的方法
        static Shape GetShape()
        {
            Random random = new Random();
            int shapeType = random.Next(1, 4); // 生成1到3之间的随机数
    
            switch (shapeType)
            {
                case 1:
                    return new Circle(random.Next(5, 20)); // 半径5到19的圆
                case 2:
                    return new Square(random.Next(5, 20)); // 边长5到19的正方形
                case 3:
                    return new Rectangle(random.Next(5, 20), random.Next(5, 20)); // 长宽5到19的矩形
                default:
                    return null; // 实际上不会执行到这,只是为了完整性
            }
        }
    
    }
    

    这个示例,首先定义了一个抽象基类Shape,以及继承自它的Circle、Square和Rectangle具体形状类。GetShape方法随机返回一个形状实例,用于演示switch语句中的模式匹配。

    运行结果:
    在这里插入图片描述

    与C++的差异-case穿透(Fall-through)

    C++允许Switch语句中的case标签不使用break语句,这会导致执行完一个case块后,控制流会“穿透”到下一个case块,直到遇到break或Switch结构结束。这种机制有时候用于执行多个case共有的代码块,但也很容易造成逻辑错误,因为开发者可能无意中忘记写break。

    C#则采取了更为严格的策略,不允许Case穿透。一旦某个case没有显式的break、goto case或throw语句、return关键字,程序会直接报错。这种设计有助于减少因忘记写break而导致的错误,使得代码更易于理解和维护。

    但在某种写法下,C#也是可以穿透的,在文章后面会讲解。

    下一篇文章

    C#的Switch语句3

  • 相关阅读:
    c++中的继承
    buuctf_练[羊城杯2020]easyphp
    Aspose.OMR for .NET 22.11.X Crack
    Linux学习记录——일 基本指令(1)
    static成员,代码块,内部类
    专访乐凯撒CTO黄道泳:看一盒披萨背后的技术之路
    Re:从零开始的C++世界——(一)入门基础
    E-R图
    DSL查询语法
    【算法】二分查找-20231120
  • 原文地址:https://blog.csdn.net/weixin_44499065/article/details/139800313