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

news2025/2/28 0:31:55

文章目录

  • switch语法结构
  • case
    • 具体的值
    • 枚举值
    • 字符串
    • const关键字
  • 如果没有匹配的值
    • default语句不一定要在最后
  • 模式匹配
  • 与C++的差异-case穿透(Fall-through)
  • 下一篇文章

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1841415.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Pyshark——安装、解析pcap文件

1、简介 PyShark是一个用于网络数据包捕获和分析的Python库,基于著名的网络协议分析工具Wireshark和其背后的libpcap/tshark库。它提供了一种便捷的方式来处理网络流量,适用于需要进行网络监控、调试和研究的场景。以下是PyShark的一些关键特性和使用方…

顺势而为:雷军、小米与创业成功的深层思考

一、引言 在当今快速发展的商业环境中,成功的企业家如马云和雷军,都以其独特的商业智慧和不懈的勤奋精神赢得了业界的尊重。然而,当我们深入探讨他们的成功之道时,会发现一个更为核心的因素——“顺势而为”。本文将基于雷军对不…

HTML静态网页成品作业(HTML+CSS+JS)——我的家乡福州介绍网页(3个页面)

🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,使用Javacsript代码实现图片轮播,共有3个页面。 二、作品…

Linux mongodb安装及简单使用

说明:本文章主要是对mongodb的单击安装 1.创建文件夹,准备安装包 cd /user/local mkdir tools 2.解压mongodb包 mkdir mongodb tar -xvf mongodb-linux-x86_64-rhel70-5.0.11.tgz -C mongodb 3.进入解压目录 cd mongodb cd mongodb-linux-x86_64-…

spark 整合 yarn

spark 整合 yarn 1、在master节点上停止spark集群 cd /usr/local/soft/spark-2.4.5/sbin ./stop-all.sh 2、spark整合yarn只需要在一个节点整合, 可以删除node1 和node2中所有的spark文件 分别在node1、node2 的/usr/local/soft目录运行 rm -rf spark-2.4.…

千脑计划:模拟人类大脑皮层,开启AI新纪元

随着科技的飞速发展,人工智能已成为当今时代的热门话题。然而,目前主流的深度神经网络虽然取得了显著成就,但也面临着能耗高、稳定性差等问题。为了解决这些挑战,一项名为“千脑计划”的宏伟项目应运而生,旨在通过模仿…

Nacos配置中心不可用会有什么影响

服务端: Nacos的数据存储接口 com.alibaba.nacos.config.server.service.DataSourceService 有两种实现: 如果指定了mysq 作为数据库,则必须使用 mysql 如果是 集群方式部署Nacos,则必须使用mysql 如果是单例方式部署 并且 没…

【因果推断python】37_断点回归3

目录 羊皮效应和模糊 RDD(Fuzzy RDD) 麦克雷测试(McCrary Test) 关键思想 羊皮效应和模糊 RDD(Fuzzy RDD) 关于教育对收入的影响,经济学有两种主要观点。第一个是广为人知的论点,…

springboot应用cpu飙升的原因排除

1、通过top或者jps命令查到是那个java进程, top可以看全局那个进程耗cpu,而jps则默认是java最耗cpu的,比如找到进程是196 1.1 top (推荐)或者jps命令均可 2、根据第一步获取的进程号,查询进程里那个线程最占用cpu,发…

C++ | Leetcode C++题解之第168题Excel表列名称

题目: 题解: class Solution { public:string convertToTitle(int columnNumber) {string ans;while (columnNumber > 0) {--columnNumber;ans columnNumber % 26 A;columnNumber / 26;}reverse(ans.begin(), ans.end());return ans;} };

计算机组成原理---Cache的基本工作原理习题

对应知识点: Cache的基本原理 1.某存储系统中,主存容量是Cache容量的4096倍,Cache 被分为 64 个块,当主存地址和Cache地址采用直接映射方式时,地址映射表的大小应为()(假设不考虑一致维护和替…

C#.Net筑基-类型系统②常见类型

01、结构体类型Struct 结构体 struct 是一种用户自定义的值类型,常用于定义一些简单(轻量)的数据结构。对于一些局部使用的数据结构,优先使用结构体,效率要高很多。 可以有构造函数,也可以没有。因此初始…

SpringCloud Alibaba Sentinel 流量控制之流控模式实践总结

官网文档:https://sentinelguard.io/zh-cn/docs/flow-control.html wiki地址:https://github.com/alibaba/Sentinel/wiki/%E6%B5%81%E9%87%8F%E6%8E%A7%E5%88%B6 本文版本:spring-cloud-starter-alibaba:2.2.0.RELEASE 如下图所…

【归并排序】| 详解归并排序 力扣912

🎗️ 主页:小夜时雨 🎗️专栏:归并排序 🎗️如何活着,是我找寻的方向 目录 1. 题目解析2. 代码 1. 题目解析 题目链接: https://leetcode.cn/problems/sort-an-array/ 我们上道题讲过归并排序的核心代码&a…

idea 创建properties文件,解决乱码

设置properties文件编码 点击file->Settings File Encodings->设置utf-8 重新创建.properties文件才生效

MySQL的自增 ID 用完了,怎么办?

MySQL 自增 ID 一般用的数据类型是 INT 或 BIGINT,正常情况下这两种类型可以满足大多数应用的需求。 当然也有不正常的情况,当达到其最大值时,尝试插入新的记录会导致错误,错误信息类似于: ERROR 167 (22003): Out o…

算法期末整理(正在更新中)

一 算法概述 算法的概念 通俗地讲,算法是指解决问题的一种方法或一个过程。更严格地讲,算法是由若干条指令组成的有穷序列。 算法的性质 1.输入:有0个或多个由外部提供的量作为算法的输入。 2.输出:算法产生至少一个量作为输出。…

【机器学习300问】126、词嵌入(Word Embedding)是什么意思?

人类的文字,作为一种高度抽象化的符号系统,承载着丰富而复杂的信息。为了让电脑也能像人类一样理解并处理这些文字,科学家们不断探索各种方法,以期将人类的语言转化为计算机能够理解的格式。 一、One-Hot编码的不足 在自然语言处…

每月策略会议

周一顾问策略会议,对于企业辅导而言,领导力是可以培训的,而决策力不是靠培训就能达成,是需要反复训练和反思。从最为关心的一个状况出发,去行动才会有结果,有了结果反思我们的假设是否有盲区是否有误才有可…

LVGL开发教程-Grid(网格布局)

系列文章目录 知不足而奋进 望远山而前行 目录 系列文章目录 文章目录 前言 1. 常用方法 2. 代码实现 总结 前言 网格布局(Grid Layout)是一种强大的布局方式,它允许将项目按照行和列的二维表格方式进行排列。LVGL(Little…