switch 语句
switch 语句根据与匹配表达式匹配的模式来选择要执行的语句列表,如以下示例所示:
DisplayMeasurement(-4); // Output: Measured value is -4; too low.
DisplayMeasurement(5); // Output: Measured value is 5.
DisplayMeasurement(30); // Output: Measured value is 30; too high.
DisplayMeasurement(double.NaN); // Output: Failed measurement.
void DisplayMeasurement(double measurement)
{
switch (measurement)
{
case < 0.0:
Console.WriteLine($"Measured value is {measurement}; too low.");
break;
case > 15.0:
Console.WriteLine($"Measured value is {measurement}; too high.");
break;
case double.NaN:
Console.WriteLine("Failed measurement.");
break;
default:
Console.WriteLine($"Measured value is {measurement}.");
break;
}
}
在上述示例中,switch 语句使用以下模式:
关系模式(在 C# 9.0 及更高版本中可用):将表达式结果与常量进行比较。
常量模式:测试表达式结果是否等于常量。
重要
有关 switch 语句支持的模式的信息,请参阅模式。
上述示例还展示了 default case。 default case 指定匹配表达式与其他任何 case 模式都不匹配时要执行的语句。 如果匹配表达式与任何 case 模式都不匹配,且没有 default case,控制就会贯穿 switch 语句。
switch 语句执行第一个 switch 部分中的语句列表,其 case 模式与匹配表达式匹配,并且它的 case guard(如果存在)求值为 true 。 switch 语句按文本顺序从上到下对 case 模式求值。 编译器在 switch 语句包含无法访问的 case 时会生成错误。 这种 case 已由大写字母处理或其模式无法匹配。
可以为 switch 语句的一部分指定多个 case 模式,如以下示例所示:
DisplayMeasurement(-4); // Output: Measured value is -4; out of an acceptable range.
DisplayMeasurement(50); // Output: Measured value is 50.
DisplayMeasurement(132); // Output: Measured value is 132; out of an acceptable range.
void DisplayMeasurement(int measurement)
{
switch (measurement)
{
case < 0:
case > 100:
Console.WriteLine($"Measured value is {measurement}; out of an acceptable range.");
break;
default:
Console.WriteLine($"Measured value is {measurement}.");
break;
}
}
在 switch 语句中,控制不能从一个 switch 部分贯穿到下一个 switch 部分。 如本部分中的示例所示,通常使用每个 switch 部分末尾的 break 语句将控制从 switch 语句传递出去。 还可使用 return 和 throw 语句将控制从 switch 语句传递出去。 若要模拟贯穿行为,将控制传递给其他 switch 部分,可使用 goto 语句。
在表达式上下文中,可使用 switch 表达式,根据与表达式匹配的模式,对候选表达式列表中的单个表达式进行求值。
Case guard
case 模式可能表达功能不够,无法指定用于执行 switch 部分的条件。 在这种情况下,可以使用 case guard。 这是一个附加条件,必须与匹配模式同时满足。 case guard 必须是布尔表达式。 可以在模式后面的 when 关键字之后指定一个 case guard,如以下示例所示:
DisplayMeasurements(3, 4); // Output: First measurement is 3, second measurement is 4.
DisplayMeasurements(5, 5); // Output: Both measurements are valid and equal to 5.
void DisplayMeasurements(int a, int b)
{
switch ((a, b))
{
case (> 0, > 0) when a == b:
Console.WriteLine($"Both measurements are valid and equal to {a}.");
break;
case (> 0, > 0):
Console.WriteLine($"First measurement is {a}, second measurement is {b}.");
break;
default:
Console.WriteLine("One or both measurements are not valid.");
break;
}
}
switch 表达式 - 使用 switch 关键字的模式匹配表达式
可以使用 switch 表达式,根据与输入表达式匹配的模式,对候选表达式列表中的单个表达式进行求值。 有关在语句上下文中支持 switch 类语义的 switch 语句的信息。
下面的示例演示了一个 switch 表达式,该表达式将在线地图中表示视觉方向的 enum 中的值转换为相应的基本方位:
public static class SwitchExample
{
public enum Direction
{
Up,
Down,
Right,
Left
}
public enum Orientation
{
North,
South,
East,
West
}
public static Orientation ToOrientation(Direction direction) => direction switch
{
Direction.Up => Orientation.North,
Direction.Right => Orientation.East,
Direction.Down => Orientation.South,
Direction.Left => Orientation.West,
_ => throw new ArgumentOutOfRangeException(nameof(direction), $"Not expected direction value: {direction}"),
};
public static void Main()
{
var direction = Direction.Right;
Console.WriteLine($"Map view direction is {direction}");
Console.WriteLine($"Cardinal orientation is {ToOrientation(direction)}");
// Output:
// Map view direction is Right
// Cardinal orientation is East
}
}
上述示例展示了 switch 表达式的基本元素:
后跟 switch 关键字的表达式。 在上述示例中,这是 direction 方法参数。
switch expression arm,用逗号分隔。 每个 switch expression arm 都包含一个模式、一个可选的 case guard、=> 标记和一个表达式 。
在上述示例中,switch 表达式使用以下模式:
常数模式:用于处理 Direction 枚举的定义值。
弃元模式:用于处理没有相应的 Direction 枚举成员的任何整数值(例如 (Direction)10)。 这会使 switch 表达式详尽。
switch 表达式的结果是第一个 switch expression arm 的表达式的值,该 switch expression arm 的模式与范围表达式匹配,并且它的 case guard(如果存在)求值为 true。 switch expression arm 按文本顺序求值。
如果无法选择较低的 switch expression arm,编译器会发出错误,因为较高的 switch expression arm 匹配其所有值。
Case guard
模式或许表现力不够,无法指定用于计算 arm 的表达式的条件。 在这种情况下,可以使用 case guard。 case guard 是一个附加条件,必须与匹配模式同时满足。 case guard 必须是布尔表达式。 可以在模式后面的 when 关键字之后指定一个 case guard,如以下示例所示:
public readonly struct Point
{
public Point(int x, int y) => (X, Y) = (x, y);
public int X { get; }
public int Y { get; }
}
static Point Transform(Point point) => point switch
{
{ X: 0, Y: 0 } => new Point(0, 0),
{ X: var x, Y: var y } when x < y => new Point(x + y, y),
{ X: var x, Y: var y } when x > y => new Point(x - y, y),
{ X: var x, Y: var y } => new Point(2 * x, 2 * y),
};