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语句进行判断。