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

文章目录

  • 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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Shiro550 反序列化漏洞(CVE-2016-4437)

目录 Shiro介绍 漏洞原理 判断是否存在漏洞 利用ShiroExploit工具执行命令: 利用shiro-exploit工具综合利用工具执行命令: 这一篇是参考别的师傅的好文章对Shiro550反序列化漏洞的学习和练习 Shiro介绍 Apache Shiro是一个强大易用的java安全框架…

ASP.NET MVC企业级程序设计(增删,页面水平排列,字符串拼接,非空,添加框内默认提示)

目录 题目: 实现过程 控制器代码 DAL BLL Index Deile 题目: 实现过程 控制器代码 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using MvcApplication1.Models;namespac…

Tensorflow入门实战 T05-运动鞋识别

目录 一、完整代码 二、训练过程 (1)打印2行10列的数据。 (2)查看数据集中的一张图片 (3)训练过程(训练50个epoch) (4)训练结果的精确度 三、遇到的问…

Docker环境离线安装

Docker环境离线安装 下载下列.deb包 sudo *.deb

【PyQt5】python桌面级应用开发:PyQt5介绍,开发环境搭建快速入门

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…

天津媒体邀约,及媒体名单?

传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 媒体宣传加速季,100万补贴享不停,一手媒体资源,全国100城线下落地执行。详情请联系胡老师。 天津作为中国北方的重要城市,拥有丰富的媒体资…

Jenkins+K8s实现持续集成(二)

部署前呢,要先把jenkins搭建好。 同时呢已经有了k8s的环境。 基于以上两步已经有了的情况,继续要实现jenkinsk8s持续集成,需要先准备四个文件: Dockerfile首先要准备好一个Dockerfile文件,用于构建Docker镜像的文本…

最新版本IntelliJ IDEA安装与“坤活”使用

最新版本IntelliJ IDEA安装与“科学”使用 IntelliJ IDEA安装与坤活下载安装坤活idea1.将下面两个压缩文件解压到安装位置,注意路径不要包含中文空格等特殊符号2.双击 install-all-users.vbs ,然后点击确定,等到出现 Done的弹窗3. 打开idea复…

函数依赖集等价、最小函数依赖集

一、函数依赖集等价 1、定义 假设F、G为一个关系模式上的两个函数依赖集,若,则称F和G是等价的,也可称F和G 互相覆盖。 2、判断 (1)引理3: 的充分必要条件是且 (2)两步走&…

密码学及其应用——为什么选择接近的质数因子对RSA加密算法不安全?

RSA加密算法是一种广泛使用的非对称加密算法,它的安全性依赖于大整数分解的难度。具体来说,RSA算法生成的公钥包含一个大整数N,这是两个大质数p和q的乘积。然而,如果这两个质数p和q太接近,则可以相对容易地对N进行因式…

Study--Oracle-04-SQL练习

一、SQL语句思维导图 二、SQL练习 -- 以employee_id 为排序,列出前5个人 -- FETCH select employee_id,first_name from employees order by employee_id FETCH FIRST 5 rows only; -- 以employee_id 为排序,从第6个人开始 到第10个人 -- offset …

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

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

【Redis】如何保证缓存和数据库的一致性

目录 背景问题思路 三个经典的缓存模式Cache-Aside读缓存写缓存为什么是删除旧缓存而不是更新旧缓存?为什么不先删除旧的缓存,然后再更新数据库? 延迟双删如何确保原子性 Read-Through/Write-ThroughRead-ThroughWrite-Through Write Behind …

Ubuntu22.04 下安装Curl库

1. apt 安装: sudo apt-get install curl 2. 官网压缩包: 下载地址:curl downloads wget https://curl.haxx.se/download/curl-7.78.0.tar.gz tar -xzvf curl-7.78.0.tar.gz cd curl-7.78.0 ./configure --with-openssl make sudo make i…

ubuntu系统上快速直接获取ip地址

文章目录 前言总结 前言 ubuntu系统上查看ip地址 $ hostname -I示例输出: 192.168.1.10总结 作者:加辣椒了吗? 简介:憨批大学生一枚,喜欢在博客上记录自己的学习心得,也希望能够帮助到你们!

基于若依的ruoyi-nbcio流程管理系统增加所有任务功能(一)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码: https://gitee.com/nbacheng/ruoyi-nbcio 演示地址:RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码: h…

CMake个人理解和使用

100编程书屋_孔夫子旧书网 前言 CMake是一个构建工具,通过它可以很容易创建跨平台的项目。通常使用它构建项目要分两步,通过源代码生成工程文件,通过工程文件构建目标产物(可能是动态库,静态库,也可能是可执行程序)。使用CMake的一个主要优势是在多平台或者多人协作的…

Python学习打卡:day10

day10 笔记来源于:黑马程序员python教程,8天python从入门到精通,学python看这套就够了 目录 day1073、文件的读取操作文件的操作步骤open()打开函数mode常用的三种基础访问模式读操作相关方法read()方法readlines()方法readline()方法for循…

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

题目&#xff1a; 题解&#xff1a; func convertToTitle(columnNumber int) string {ans : []byte{}for columnNumber > 0 {columnNumber--ans append(ans, Abyte(columnNumber%26))columnNumber / 26}for i, n : 0, len(ans); i < n/2; i {ans[i], ans[n-1-i] ans[n…