C#的switch的用法及模式匹配

  switch-case语句经常被认为是if-else语句的替代品,但是在众多程序语言中还是能见到switch的存在,这很大程度上是因为switch更实用,这一点在C#中更能提现。

  简单的语法就不说了,一个简单的switch用法:  

复制代码
    switch (cmd)
    {
        case "start": Console.WriteLine("start"); break;
        case "pause": Console.WriteLine("pause"); break;
        case "stop": Console.WriteLine("stop"); break;
        default: Console.WriteLine("invalid commond"); break;
    }
复制代码

  注意,C#规定,各个case语句不允许贯穿,也就是说每个case语句执行完之后,必须显示的退出,比如使用break、goto、return、throw等语句退出,但是C#又允许你使用goto case、goto default语句来实现贯穿(注意使用,避免造成死循环):  

复制代码
    string color = "blue";
    switch (color)
    {
        case "red": Console.WriteLine("red"); goto default;
        case "green": Console.WriteLine("green"); goto case "red";
        case "blue": Console.WriteLine("blue"); goto case "green";
        default: Console.WriteLine("default"); break;
    }

    //输出:
    //blue
    //green
    //red
    //default
复制代码

  虽然C#中switch不允许case贯穿,但是运行多个case语句组合:  

复制代码
    switch (dayOfWeek)
    {
        case DayOfWeek.Monday: Console.WriteLine("weekend"); break;
        case DayOfWeek.Tuesday: Console.WriteLine("weekend"); break;
        case DayOfWeek.Wednesday: Console.WriteLine("weekend"); break;
        case DayOfWeek.Thursday: Console.WriteLine("weekend"); break;
        case DayOfWeek.Friday: Console.WriteLine("weekend"); break;
        case DayOfWeek.Saturday:
        case DayOfWeek.Sunday: Console.WriteLine("weekend"); break;
    }
复制代码

  C# 6.0及之前版本的switch中,匹配表达式只支持字符串、字符、整形(如int、long等)、bool、枚举几个类型,因此switch的作用很有限,被认为是if-else的替代品也不无道理。

  C#7.0之后,switch的限制得到放宽,每个case语句不在是一个常量,而是一个模式,更多关于模式内容见:C#中的模式匹配

  看看一些简单的使用例子:

  1、声明模式  

复制代码
    public void ShowMessage(object value)
    {
        switch (value)
        {
            case int i: Console.WriteLine($"value is int:{i}"); break;
            case long l: Console.WriteLine($"value is long:{l}"); break;
            case bool b: Console.WriteLine($"value is bool:{b}"); break;
            case string s: Console.WriteLine($"value is string:{s}"); break;
            default: Console.WriteLine($"value is object"); break;
        }
    }
复制代码

  2、类型模式

  类型模式可以理解为在声明模式中使用了弃元:  

复制代码
    public void ShowMessage(object value)
    {
        switch (value)
        {
            case int: Console.WriteLine($"value is int"); break;
            case long: Console.WriteLine($"value is long"); break;
            case bool: Console.WriteLine($"value is bool"); break;
            case string: Console.WriteLine($"value is string"); break;
            default: Console.WriteLine($"value is object"); break;
        }
    }
复制代码

  3、常量模式

  常量模式可以理解为原来C#6.0及之前的用法:  

复制代码
   switch (score)
   {
       case 10: 
       case 9: Console.WriteLine("excellent"); break;
       case 8: Console.WriteLine("good"); break;
       case 7: 
       case 6: Console.WriteLine("fair"); break;
       default: Console.WriteLine("poor"); break;
   }
复制代码

  4、关系模式  

复制代码
    switch (score)
    {
        case >= 80: Console.WriteLine("excellent"); break;
        case >= 60: Console.WriteLine("good"); break;
        default: Console.WriteLine("poor"); break;
    }
复制代码

  5、逻辑模式  

复制代码
    switch (value)
    {
        case 0: Console.WriteLine("value is 0"); break;
        case not 0 and (100 or -100): Console.WriteLine("abs(value)==100"); break;
        case not 0 and (> 0 and < 100): Console.WriteLine("value is positive and less than 100"); break;
        case not 0 and > 0: Console.WriteLine("value is positive and greater than 100"); break;
        case < -100 or (< 0 and > -100): Console.WriteLine("value is negative and not equals -100"); break;
    }
复制代码

  6、属性模式

复制代码
    switch (time)
    {
        case { Year: 2020 or 2021, Month: <= 6, Day: 1 } t: Console.WriteLine($"the first day of every month in the first half of 2020 and 2021"); break;
        case { Year: not 2022 }: Console.WriteLine($"not 2022"); break;
        case { DayOfWeek: not DayOfWeek.Sunday and not DayOfWeek.Saturday }: Console.WriteLine($"recursion"); break;
    }
复制代码

  7、位置模式

  位置模式采用解构的特性来说明指定的模式是否匹配:  

复制代码
    public record Point2D(int X, int Y);//记录可以解构
    static void Print(Point2D point)
    {
        switch (point)
        {
            case ( > 0, > 0): Console.WriteLine("first quadrant"); break;
            case ( < 0, > 0): Console.WriteLine("second quadrant"); break;
            case ( < 0, < 0): Console.WriteLine("third quadrant"); break;
            case ( > 0, < 0): Console.WriteLine("fourth quadrant"); break;
            default: Console.WriteLine("coordinate axis"); break;
        }
    }
复制代码

  8、Var模式

  Var模式往往和属性模式和位置模式结合,用于提取属性变量值:  

复制代码
    switch (point)
    {
        case (var x, var y, var z): Console.WriteLine($"3D point:({x},{y},{z})"); break;//在位置模式中使用
        case Point2D { X: var x, Y: var y }: Console.WriteLine($"2D point:({x},{y})"); break;//在属性模式中使用
        default: Console.WriteLine("others"); break;
    }
复制代码

  9、弃元模式

  弃元模式在switch语句中用的不多,但是在switch表达式中使用的多:  

复制代码
    var result = score switch
    {
        >= 80 => "excellent",
        >= 60 => "good",
        _ => "poor" //弃元在switch表达式中就相当于default
    };
复制代码

 

  switch表达式

  从C#8.0开始,switch有了一种新的用法:switch表达式,它的主要就是类似于sql语句中的case-when的用法,可以方便的进行匹配输出,格式:  

复制代码
    var_name switch 
    {
        match_expr1 => value1,
        match_expr2 => value2,
        match_expr3 => value3,
        _ => default_value
    }
复制代码

  这里的每一个 match_expr 是一个匹配模式,相当于switch语句中的case语句的模式内容,它的含义就是,如果match_expr模式匹配成功,那么就返回对应的值,需要注意的是,switch表达式是输出语句!

  比如之前有这样的一个枚举:  

复制代码
    public enum Color
    {
        Unknown,
        Red,
        Blue,
        Green
    }    
复制代码

  使用中我们可能会需要进行一些转换,可能会用到 if 判断:  

复制代码
    static string Convert(Color color)
    {
        string rbg;
        if (color == Color.Red)
        {
            rbg = "#FF0000";
        }
        else if (color == Color.Blue)
        {
            rbg = "#0000FF";
        }
        else if (color == Color.Green)
        {
            rbg = "#00FF00";
        }
        else
        {
            rbg = "";
        }
        return rbg;
    }
复制代码

  或者使用switch语句:  

复制代码
    static string Convert(Color color)
    {
        string rbg;
        switch (color)
        {
            case Color.Red:rbg = "#FF0000";break;
            case Color.Blue: rbg = "#0000FF"; break;
            case Color.Green: rbg = "#00FF00"; break;
            default: rbg = ""; break;
        }
        return rbg;
    }
复制代码

  现在使用switch表达式可简写Convert方法:  

复制代码
    static string Convert(Color color)
    {
        return color switch
        {
            Color.Red => "this is red",
            Color.Blue => "this is blue",
            Color.Green => "this is green",
            _ => "",
        };
    }
复制代码

  这样看起简洁密聊了许多。

 

  case-when

  无论是在switch语句中,还是在switch表达式中,在模式匹配之后,我们可以跟着一个when语句,对匹配结果做进一步的判断:  

  比如一些简单的例子:    

复制代码
    static string Convert(object color)
    {
        return color switch
        {
            Color c when c == Color.Red => "red",
            Color c when c == Color.Blue => "blue",
            Color c when c == Color.Green => "green",
            _ => "unknown color",
        };
    }
复制代码

  再比如:

复制代码
    var desc = shape switch
    {
        Point p when p.IsEmpty => "empty point",
        Point { X: var x, Y: var y } when object.Equals(x, y) => "point:x=y",
        Point => $"point",
        Rectangle { Width: var width, Height: var height } when width == height => "square",
        Rectangle => "rectangle",
        _ => "other shape"
    };
复制代码

  when语句弥补了模式的一些不足,可以让判断更加精确而不用我们自己在后续代码中使用if语句进行判断。

 

 

出处:https://www.cnblogs.com/shanfeng1000/p/14951498.html

=======================================================================================

关于C#8.0的SwitchCaseWhen的用法

switch case when

8.0新特性,把贼好用!(熟悉T-SQL的会感觉很亲切,新的switch扩展变得和T-SQL的Case When Then End类似,可以支持不等式区间的布尔表达式) ,其可读性吊锤if else!

语法

       switch (fileName)
            {
                case string s when s.Contains(".xsd"): // or EndsWith, etc
                    // todo
                    break;
                default:
                    break;
            }

示例测试程序:

class Person
    {
        public int grade { get; set; }
        public string name { get; set; }
        public string level { get; set; }
    }

IList<Person> persons= new List<Person>()
  {
      new Person{ grade = 50, name = "A_People", level = "None" },
      new Person{ grade = 70, name = "B_People", level = "None" },
      new Person{ grade = 91, name = "C_People", level = "None" }
  };

  foreach (Person p in persons)
  {
      switch (p)
      {
          case Person obj when obj.grade < 60:
              {
                  obj.level = "不及格";
                  break;
              }
          case Person obj when obj.grade > 60 && obj.grade <= 70:
              {
                  obj.level = "及格";
                  break;
              }
          case Person obj when obj.grade > 60 && obj.grade <= 70:
              {
                  obj.level = "良好";
                  break;
              }
          case Person obj when obj.grade >= 90:
              {
                  obj.level = "优秀";
                  break;
              }
          default:
              {
                  Person.level = "None";
                  break;
              }
      }
      Console.WriteLine($"此人的:{p.name} 成绩:{p.level}");

 

出处:https://blog.csdn.net/huatoudd/article/details/119317610

posted on 2022-12-01 15:38  jack_Meng  阅读(11376)  评论(0编辑  收藏  举报

导航