switch(C# 参考)switch (C# reference)

本文介绍 switch 语句。This article covers the switch statement. 有关 switch 表达式(在 C# 8.0 中引入)的信息,请参阅 表达式和运算符部分中有关 switch 表达式的文章。For information on the switch expression (introduced in C# 8.0), see the article on switch expressions in the expressions and operators section.

switch 是一个选择语句,它根据与匹配表达式匹配的模式,从候选列表中选择单个开关部分进行执行。switch is a selection statement that chooses a single switch section to execute from a list of candidates based on a pattern match with the match expression.

using System;

public class Example
{
   public static void Main()
   {
      int caseSwitch = 1;

      switch (caseSwitch)
      {
          case 1:
              Console.WriteLine("Case 1");
              break;
          case 2:
              Console.WriteLine("Case 2");
              break;
          default:
              Console.WriteLine("Default case");
              break;
      }
   }
}
// The example displays the following output:
//       Case 1

如果针对 3 个或更多条件测试单个表达式,switch 语句通常用作 if-else 构造的替代项。The switch statement is often used as an alternative to an if-else construct if a single expression is tested against three or more conditions. 例如,以下 switch 语句确定类型为 Color 的变量是否具有三个值之一:For example, the following switch statement determines whether a variable of type Color has one of three values:

using System;

public enum Color { Red, Green, Blue }

public class Example
{
   public static void Main()
   {
      Color c = (Color) (new Random()).Next(0, 3);
      switch (c)
      {
         case Color.Red:
            Console.WriteLine("The color is red");
            break;
         case Color.Green:
            Console.WriteLine("The color is green");
            break;
         case Color.Blue:
            Console.WriteLine("The color is blue");
            break;
         default:
            Console.WriteLine("The color is unknown.");
            break;
      }
   }
}

它相当于使用 if-else 构造的以下示例。It's equivalent to the following example that uses an if-else construct.

using System;

public enum Color { Red, Green, Blue }

public class Example
{
   public static void Main()
   {
      Color c = (Color) (new Random()).Next(0, 3);
      if (c == Color.Red)
         Console.WriteLine("The color is red");
      else if (c == Color.Green)
         Console.WriteLine("The color is green");
      else if (c == Color.Blue)
         Console.WriteLine("The color is blue");
      else
         Console.WriteLine("The color is unknown.");
   }
}
// The example displays the following output:
//       The color is red

匹配表达式The match expression

匹配表达式提供与 case 标签中的模式相匹配的值。The match expression provides the value to match against the patterns in case labels. 语法为:Its syntax is:

   switch (expr)

在 C# 6 及更低版本中,匹配表达式必须是返回以下类型值的表达式:In C# 6 and earlier, the match expression must be an expression that returns a value of the following types:

从 C# 7.0 开始,匹配表达式可以是任何非 null 表达式。Starting with C# 7.0, the match expression can be any non-null expression.

开关部分The switch section

switch 语句包含一个或多个开关部分。A switch statement includes one or more switch sections. 每个 switch 部分包含一个或多个 case 标签(case 或 default 标签),后接一个或多个语句。Each switch section contains one or more case labels (either a case or default label) followed by one or more statements. switch 语句最多可包含一个置于任何 switch 部分中的 default 标签。The switch statement may include at most one default label placed in any switch section. 以下示例显示了一个简单的 switch 语句,该语句包含三个 switch 部分,每个部分包含两个语句。The following example shows a simple switch statement that has three switch sections, each containing two statements. 第二个 switch 部分包含 case 2:case 3: 标签。The second switch section contains the case 2: and case 3: labels.

switch 语句中可以包含任意数量的开关部分,每个开关部分可以具有一个或多个 case 标签,如以下示例所示。A switch statement can include any number of switch sections, and each section can have one or more case labels, as shown in the following example. 但是,任何两个 case 标签不可包含相同的表达式。However, no two case labels may contain the same expression.

using System;

public class Example
{
   public static void Main()
   {
      Random rnd = new Random();
      int caseSwitch = rnd.Next(1,4);

      switch (caseSwitch)
      {
          case 1:
              Console.WriteLine("Case 1");
              break;
          case 2:
          case 3:
              Console.WriteLine($"Case {caseSwitch}");
              break;
          default:
              Console.WriteLine($"An unexpected value ({caseSwitch})");
              break;
      }
   }
}
// The example displays output like the following:
//       Case 1

switch 语句执行中只有一个开关部分。Only one switch section in a switch statement executes. C# 禁止从一个 switch 部分继续执行到下一个 switch 部分。C# doesn't allow execution to continue from one switch section to the next. 因此,下面的代码生成编译器错误 CS0163:“控件不能从一个 case 标签 (<case label>) 贯穿到另一个 case 标签。”Because of this, the following code generates a compiler error, CS0163: "Control cannot fall through from one case label (<case label>) to another."

switch (caseSwitch)
{
    // The following switch section causes an error.
    case 1:
        Console.WriteLine("Case 1...");
        // Add a break or other jump statement here.
    case 2:
        Console.WriteLine("... and/or Case 2");
        break;
}

通常通过使用 breakgotoreturn 语句显式退出开关部分来满足此要求。This requirement is usually met by explicitly exiting the switch section by using a break, goto, or return statement. 不过,以下代码也有效,因为它确保程序控制权无法贯穿到 default switch 部分。However, the following code is also valid, because it ensures that program control can't fall through to the default switch section.

switch (caseSwitch)
{
    case 1:
        Console.WriteLine("Case 1...");
        break;
    case 2:
    case 3:
        Console.WriteLine("... and/or Case 2");
        break;
    case 4:
        while (true)
           Console.WriteLine("Endless looping. . . .");
    default:
        Console.WriteLine("Default value...");
        break;
}

在 case 标签与匹配表达式匹配的开关部分中执行语句列表时,先执行第一个语句,再执行整个语句列表,通常执行到跳转语句(如 breakgoto casegoto labelreturnthrow)为止。Execution of the statement list in the switch section with a case label that matches the match expression begins with the first statement and proceeds through the statement list, typically until a jump statement, such as a break, goto case, goto label, return, or throw, is reached. 此时,控件在 switch 语句之外进行传输或传输到另一个 case 标签。At that point, control is transferred outside the switch statement or to another case label. 如果使用的是 goto 语句,必须将控制权移交给常量标签。A goto statement, if it's used, must transfer control to a constant label. 此限制是必要的,因为尝试将控制权移交给非常数标签可能会产生不良的副作用,如将控制权移交给代码中的意外位置,或创建无限循环。This restriction is necessary, since attempting to transfer control to a non-constant label can have undesirable side-effects, such transferring control to an unintended location in code or creating an endless loop.

Case 标签Case labels

每个 case 标签指定一个模式与匹配表达式(前面示例中的 caseSwitch 变量)进行比较。Each case label specifies a pattern to compare to the match expression (the caseSwitch variable in the previous examples). 如果它们匹配,则将控件传输到包含首次匹配 case 标签的开关部分。If they match, control is transferred to the switch section that contains the first matching case label. 如果 case 标签模式与匹配表达式不匹配,控制权会转让给带 default case 标签的部分(若有)。If no case label pattern matches the match expression, control is transferred to the section with the default case label, if there's one. 如果没有 default case,将不会执行任何 switch 部分中的语句,并且会将控制权转让到 switch 语句之外。If there's no default case, no statements in any switch section are executed, and control is transferred outside the switch statement.

有关 switch 语句和模式匹配的信息,请参阅使用 switch 语句的 [模式匹配](#pattern-matching with-the-switch-statement)部分。For information on the switch statement and pattern matching, see the [Pattern matching with the switch statement](#pattern-matching with-the-switch-statement) section.

因为 C# 6 仅支持常量模式且禁止重复常量值,所以 case 标签定义了互斥值,而且只能有一个模式与匹配表达式匹配。Because C# 6 supports only the constant pattern and doesn't allow the repetition of constant values, case labels define mutually exclusive values, and only one pattern can match the match expression. 因此,case 语句显示的顺序并不重要。As a result, the order in which case statements appear is unimportant.

然而,在 C# 7.0 中,因为支持其他模式,所以 case 标签不需要定义互斥值,并且多个模式可以与匹配表达式相匹配。In C# 7.0, however, because other patterns are supported, case labels need not define mutually exclusive values, and multiple patterns can match the match expression. 因为仅执行包含匹配模式的首次开关部分中的语句,所以 case 语句显示的顺序很重要。Because only the statements in the first switch section that contains the matching pattern are executed, the order in which case statements appear is now important. 如果 C# 检测到开关部分的 case 语句或语句等效于或是先前语句的子集,它将生成编译错误 CS8120:“开关 case 已由先前 case 处理。”If C# detects a switch section whose case statement or statements are equivalent to or are subsets of previous statements, it generates a compiler error, CS8120, "The switch case has already been handled by a previous case."

以下示例说明了使用各种非互斥模式的 switch 语句。The following example illustrates a switch statement that uses a variety of non-mutually exclusive patterns. 如果你移动 case 0: switch 部分,使之不再是 switch 语句中的第一部分,C# 会生成编译器错误,因为值为零的整数是所有整数的子集(由 case int val 语句定义的模式)。If you move the case 0: switch section so that it's no longer the first section in the switch statement, C# generates a compiler error because an integer whose value is zero is a subset of all integers, which is the pattern defined by the case int val statement.

using System;
using System.Collections.Generic;
using System.Linq;

public class Example
{
   public static void Main()
   {
      var values = new List<object>();
      for (int ctr = 0; ctr <= 7; ctr++) {
         if (ctr == 2)
            values.Add(DiceLibrary.Roll2());
         else if (ctr == 4)
            values.Add(DiceLibrary.Pass());
         else
            values.Add(DiceLibrary.Roll());
      }

      Console.WriteLine($"The sum of { values.Count } die is { DiceLibrary.DiceSum(values) }");
   }
}

public static class DiceLibrary
{
   // Random number generator to simulate dice rolls.
   static Random rnd = new Random();

   // Roll a single die.
   public static int Roll()
   {
      return rnd.Next(1, 7);
   }

   // Roll two dice.
   public static List<object> Roll2()
   {
      var rolls = new List<object>();
      rolls.Add(Roll());
      rolls.Add(Roll());
      return rolls;
   }

   // Calculate the sum of n dice rolls.
   public static int DiceSum(IEnumerable<object> values)
   {
      var sum = 0;
      foreach (var item in values)
      {
            switch (item)
            {
               // A single zero value.
               case 0:
                  break;
               // A single value.
               case int val:
                  sum += val;
                  break;
               // A non-empty collection.
               case IEnumerable<object> subList when subList.Any():
                  sum += DiceSum(subList);
                  break;
               // An empty collection.
               case IEnumerable<object> subList:
                  break;
               //  A null reference.
               case null:
                  break;
               // A value that is neither an integer nor a collection.
               default:
                  throw new InvalidOperationException("unknown item type");
            }
      }
      return sum;
   }

   public static object Pass()
   {
      if (rnd.Next(0, 2) == 0)
         return null;
      else
         return new List<object>();
   }
}

你可以通过以下两种方法之一更正此问题并消除编译器警告:You can correct this issue and eliminate the compiler warning in one of two ways:

  • 更改开关部分的顺序。By changing the order of the switch sections.

  • case 标签中使用 when clause 子句。By using a when clause in the case label.

default caseThe default case

如果匹配表达式与其他任何 case 标签都不匹配,default case 指定要执行的 switch 部分。The default case specifies the switch section to execute if the match expression doesn't match any other case label. 如果没有 default case,且匹配表达式与其他任何 case 标签都不匹配,程序流就会贯穿 switch 语句。If a default case is not present and the match expression doesn't match any other case label, program flow falls through the switch statement.

default case 可以在 switch 语句中以任何顺序显示。The default case can appear in any order in the switch statement. 无论它在源代码中的顺序如何,始终都将在计算所有 case 标签后,最后计算它。Regardless of its order in the source code, it's always evaluated last, after all case labels have been evaluated.

使用 switch 语句的模式匹配Pattern matching with the switch statement

每个 case 语句定义一个模式,如果它与匹配表达式相匹配,则会导致执行其包含的开关部分。Each case statement defines a pattern that, if it matches the match expression, causes its containing switch section to be executed. 所有版本的 C# 都支持常量模式。All versions of C# support the constant pattern. 其余模式从 C# 7.0 开始支持。The remaining patterns are supported beginning with C# 7.0.

常量模式Constant pattern

常量模式测试匹配表达式是否等于指定常量。The constant pattern tests whether the match expression equals a specified constant. 语法为:Its syntax is:

   case constant:

其中 constant 是要测试的值。where constant is the value to test for. constant 可以是以下任何常数表达式:constant can be any of the following constant expressions:

  • bool 文本:truefalseA bool literal: either true or false.
  • 任何整型常数,例如 intlongbyteAny integral constant, such as an int, a long, or a byte.
  • 已声明 const 变量的名称。The name of a declared const variable.
  • 一个枚举常量。An enumeration constant.
  • 字符型文本。A char literal.
  • 字符串文本。A string literal.

常数表达式的计算方式如下:The constant expression is evaluated as follows:

  • 如果 exprconstant 均为整型类型,则 C# 相等运算符确定表示式是否返回 true(即,是否为 expr == constant)。If expr and constant are integral types, the C# equality operator determines whether the expression returns true (that is, whether expr == constant).

  • 否则,由对静态 Object.Equals(expr, constant) 方法的调用确定表达式的值。Otherwise, the value of the expression is determined by a call to the static Object.Equals(expr, constant) method.

以下示例使用常量模式来确定特定日期是否为周末、工作周的第一天、工作周的最后一天或工作周的中间日期。The following example uses the constant pattern to determine whether a particular date is a weekend, the first day of the work week, the last day of the work week, or the middle of the work week. 它根据 DayOfWeek 枚举的成员计算当前日期的 DateTime.DayOfWeek 属性。It evaluates the DateTime.DayOfWeek property of the current day against the members of the DayOfWeek enumeration.

using System;

class Program
{
    static void Main()
    {
        switch (DateTime.Now.DayOfWeek)
        {
           case DayOfWeek.Sunday:
           case DayOfWeek.Saturday:
              Console.WriteLine("The weekend");
              break;
           case DayOfWeek.Monday:
              Console.WriteLine("The first day of the work week.");
              break;
           case DayOfWeek.Friday:
              Console.WriteLine("The last day of the work week.");
              break;
           default:
              Console.WriteLine("The middle of the work week.");
              break;
        }
    }
}
// The example displays output like the following:
//       The middle of the work week.

以下示例使用常量模式在模拟自动咖啡机的控制台应用程序中处理用户输入。The following example uses the constant pattern to handle user input in a console application that simulates an automatic coffee machine.

using System;

class Example
{
   static void Main()
   {
       Console.WriteLine("Coffee sizes: 1=small 2=medium 3=large");
       Console.Write("Please enter your selection: ");
       string str = Console.ReadLine();
       int cost = 0;

       // Because of the goto statements in cases 2 and 3, the base cost of 25
       // cents is added to the additional cost for the medium and large sizes.
       switch (str)
       {
          case "1":
          case "small":
              cost += 25;
              break;
          case "2":
          case "medium":
              cost += 25;
              goto case "1";
          case "3":
          case "large":
              cost += 50;
              goto case "1";
          default:
              Console.WriteLine("Invalid selection. Please select 1, 2, or 3.");
              break;
      }
      if (cost != 0)
      {
          Console.WriteLine("Please insert {0} cents.", cost);
      }
      Console.WriteLine("Thank you for your business.");
   }
}
// The example displays output like the following:
//         Coffee sizes: 1=small 2=medium 3=large
//         Please enter your selection: 2
//         Please insert 50 cents.
//         Thank you for your business.

类型模式Type pattern

类型模式可启用简洁类型计算和转换。The type pattern enables concise type evaluation and conversion. 使用 switch 语句执行模式匹配时,会测试表达式是否可转换为指定类型,如果可以,则将其转换为该类型的一个变量。When used with the switch statement to perform pattern matching, it tests whether an expression can be converted to a specified type and, if it can be, casts it to a variable of that type. 语法为:Its syntax is:

   case type varname

其中 typeexpr 结果要转换到的类型的名称,varnameexpr 结果要转换到的对象(如果匹配成功)。where type is the name of the type to which the result of expr is to be converted, and varname is the object to which the result of expr is converted if the match succeeds. 自 C# 7.1 起,expr 的编译时类型可能为泛型类型参数。The compile-time type of expr may be a generic type parameter, starting with C# 7.1.

如果以下任一条件成立,则 case 表达式为 trueThe case expression is true if any of the following is true:

  • expr 是与 type 具有相同类型的一个实例。expr is an instance of the same type as type.

  • expr 是派生自 type 的类型的一个实例。expr is an instance of a type that derives from type. 换言之,expr 结果可以向上转换为 type 的一个实例。In other words, the result of expr can be upcast to an instance of type.

  • expr 具有属于 type 的一个基类的编译时类型,expr 还具有属于 type 或派生自 type 的运行时类型。expr has a compile-time type that is a base class of type, and expr has a runtime type that is type or is derived from type. 变量的编译时类型是其类型声明中定义的变量类型。The compile-time type of a variable is the variable's type as defined in its type declaration. 变量的运行时类型是分配给该变量的实例类型。The runtime type of a variable is the type of the instance that is assigned to that variable.

  • expr 是实现 type 接口的类型的一个实例。expr is an instance of a type that implements the type interface.

如果 case 表达式为 true,将会明确分配 varname,并且仅在开关部分中具有本地作用域。If the case expression is true, varname is definitely assigned and has local scope within the switch section only.

请注意,null 与任何类型都不匹配。Note that null doesn't match a type. 若要匹配 null,请使用以下 case 标签:To match a null, you use the following case label:

case null:

以下示例使用类型模式来提供有关各种集合类型的信息。The following example uses the type pattern to provide information about various kinds of collection types.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

class Example
{
    static void Main(string[] args)
    {
        int[] values = { 2, 4, 6, 8, 10 };
        ShowCollectionInformation(values);

        var names = new List<string>();
        names.AddRange(new string[] { "Adam", "Abigail", "Bertrand", "Bridgette" });
        ShowCollectionInformation(names);

        List<int> numbers = null;
        ShowCollectionInformation(numbers);
    }

    private static void ShowCollectionInformation(object coll)
    {
        switch (coll)
        {
            case Array arr:
               Console.WriteLine($"An array with {arr.Length} elements.");
               break;
            case IEnumerable<int> ieInt:
               Console.WriteLine($"Average: {ieInt.Average(s => s)}");
               break;
            case IList list:
               Console.WriteLine($"{list.Count} items");
               break;
            case IEnumerable ie:
               string result = "";
               foreach (var e in ie)
                  result += $"{e} ";
               Console.WriteLine(result);
               break;
            case null:
               // Do nothing for a null.
               break;
            default:
               Console.WriteLine($"A instance of type {coll.GetType().Name}");
               break;
        }
    }
}
// The example displays the following output:
//     An array with 5 elements.
//     4 items

可以创建泛型方法,使用集合的类型作为类型参数(而不是使用 object),如下面的代码所示:Instead of object, you could make a generic method, using the type of the collection as the type parameter, as shown in the following code:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

class Example
{
    static void Main(string[] args)
    {
        int[] values = { 2, 4, 6, 8, 10 };
        ShowCollectionInformation(values);

        var names = new List<string>();
        names.AddRange(new string[] { "Adam", "Abigail", "Bertrand", "Bridgette" });
        ShowCollectionInformation(names);

        List<int> numbers = null;
        ShowCollectionInformation(numbers);
    }

    private static void ShowCollectionInformation<T>(T coll)
    {
        switch (coll)
        {
            case Array arr:
               Console.WriteLine($"An array with {arr.Length} elements.");
               break;
            case IEnumerable<int> ieInt:
               Console.WriteLine($"Average: {ieInt.Average(s => s)}");
               break;
            case IList list:
               Console.WriteLine($"{list.Count} items");
               break;
            case IEnumerable ie:
               string result = "";
               foreach (var e in ie)
                  result += $"{e} ";
               Console.WriteLine(result);
               break;
            case object o:
               Console.WriteLine($"A instance of type {o.GetType().Name}");
               break;
            default:
                Console.WriteLine("Null passed to this method.");
                break;
        }
    }
}
// The example displays the following output:
//     An array with 5 elements.
//     4 items
//     Null passed to this method.

泛型版本与第一个示例有两点不同。The generic version is different than the first sample in two ways. 首先,无法使用 null case。First, you can't use the null case. 无法使用任何常量 case 是因为,编译器无法将任意类型 T 转换为除 object 之外的任何类型。You can't use any constant case because the compiler can't convert any arbitrary type T to any type other than object. 曾经的 default case 现在测试是否有非 null objectWhat had been the default case now tests for a non-null object. 也就是说,default case 测试只针对 nullThat means the default case tests only for null.

如果没有模式匹配,则可能按以下方式编写此代码。Without pattern matching, this code might be written as follows. 使用类型模式匹配可消除测试转换结果是否为 null 或执行重复转换的必要,从而生成更紧凑易读的代码。The use of type pattern matching produces more compact, readable code by eliminating the need to test whether the result of a conversion is a null or to perform repeated casts.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

class Example
{
    static void Main(string[] args)
    {
        int[] values = { 2, 4, 6, 8, 10 };
        ShowCollectionInformation(values);

        var names = new List<string>();
        names.AddRange(new string[] { "Adam", "Abigail", "Bertrand", "Bridgette" });
        ShowCollectionInformation(names);

        List<int> numbers = null;
        ShowCollectionInformation(numbers);
    }

    private static void ShowCollectionInformation(object coll)
    {
        if (coll is Array)
        {
           Array arr = (Array) coll;
           Console.WriteLine($"An array with {arr.Length} elements.");
        }
        else if (coll is IEnumerable<int>)
        {
            IEnumerable<int> ieInt = (IEnumerable<int>) coll;
            Console.WriteLine($"Average: {ieInt.Average(s => s)}");
        }
        else if (coll is IList)
        {
            IList list = (IList) coll;
            Console.WriteLine($"{list.Count} items");
        }
        else if (coll is IEnumerable)
        {
            IEnumerable ie = (IEnumerable) coll;
            string result = "";
            foreach (var e in ie)
               result += $"{e} ";
            Console.WriteLine(result);
        }
        else if (coll == null)
        {
            // Do nothing.
        }
        else
        {
            Console.WriteLine($"An instance of type {coll.GetType().Name}");
        }
    }
}
// The example displays the following output:
//     An array with 5 elements.
//     4 items

case 语句和 when 子句The case statement and the when clause

从 C# 7.0 开始,因为 case 语句不需要互相排斥,因此可以添加 when 子句来指定必须满足的附加条件使 case 语句计算为 true。Starting with C# 7.0, because case statements need not be mutually exclusive, you can add a when clause to specify an additional condition that must be satisfied for the case statement to evaluate to true. when 子句可以是返回布尔值的任何表达式。The when clause can be any expression that returns a Boolean value.

下面的示例定义了 Shape 基类、从 Shape 派生的 Rectangle 类以及从 Rectangle 派生的 Square 类。The following example defines a base Shape class, a Rectangle class that derives from Shape, and a Square class that derives from Rectangle. 它使用 when 子句,以确保 ShowShapeInfo 将已分配相等长度和宽度的 Rectangle 对象视为 Square(即使它尚未实例化为 Square 对象)。It uses the when clause to ensure that the ShowShapeInfo treats a Rectangle object that has been assigned equal lengths and widths as a Square even if it hasn't been instantiated as a Square object. 此方法不会尝试显示值为 null 的对象或面积为零的形状的相关信息。The method doesn't attempt to display information either about an object that is null or a shape whose area is zero.

using System;

public abstract class Shape
{
   public abstract double Area { get; }
   public abstract double Circumference { get; }
}

public class Rectangle : Shape
{
   public Rectangle(double length, double width)
   {
      Length = length;
      Width = width;
   }

   public double Length { get; set; }
   public double Width { get; set; }

   public override double Area
   {
      get { return Math.Round(Length * Width,2); }
   }

   public override double Circumference
   {
      get { return (Length + Width) * 2; }
   }
}

public class Square : Rectangle
{
   public Square(double side) : base(side, side)
   {
      Side = side;
   }

   public double Side { get; set; }
}

public class Circle : Shape
{
   public Circle(double radius)
   {
      Radius = radius;
   }

   public double Radius { get; set; }

   public override double Circumference
   {
      get { return 2 * Math.PI * Radius; }
   }

   public override double Area
   {
      get { return Math.PI * Math.Pow(Radius, 2); }
   }
}

public class Example
{
   public static void Main()
   {
      Shape sh = null;
      Shape[] shapes = { new Square(10), new Rectangle(5, 7),
                         sh, new Square(0), new Rectangle(8, 8),
                         new Circle(3) };
      foreach (var shape in shapes)
         ShowShapeInfo(shape);
   }

   private static void ShowShapeInfo(Shape sh)
   {
      switch (sh)
      {
         // Note that this code never evaluates to true.
         case Shape shape when shape == null:
            Console.WriteLine($"An uninitialized shape (shape == null)");
            break;
         case null:
            Console.WriteLine($"An uninitialized shape");
            break;
         case Shape shape when sh.Area == 0:
            Console.WriteLine($"The shape: {sh.GetType().Name} with no dimensions");
            break;
         case Square sq when sh.Area > 0:
            Console.WriteLine("Information about square:");
            Console.WriteLine($"   Length of a side: {sq.Side}");
            Console.WriteLine($"   Area: {sq.Area}");
            break;
         case Rectangle r when r.Length == r.Width && r.Area > 0:
            Console.WriteLine("Information about square rectangle:");
            Console.WriteLine($"   Length of a side: {r.Length}");
            Console.WriteLine($"   Area: {r.Area}");
            break;
         case Rectangle r when sh.Area > 0:
            Console.WriteLine("Information about rectangle:");
            Console.WriteLine($"   Dimensions: {r.Length} x {r.Width}");
            Console.WriteLine($"   Area: {r.Area}");
            break;
         case Shape shape when sh != null:
            Console.WriteLine($"A {sh.GetType().Name} shape");
            break;
         default:
            Console.WriteLine($"The {nameof(sh)} variable does not represent a Shape.");
            break;
      }
   }
}
// The example displays the following output:
//       Information about square:
//          Length of a side: 10
//          Area: 100
//       Information about rectangle:
//          Dimensions: 5 x 7
//          Area: 35
//       An uninitialized shape
//       The shape: Square with no dimensions
//       Information about square rectangle:
//          Length of a side: 8
//          Area: 64
//       A Circle shape

请注意,不会执行尝试测试 Shape 对象是否为 null 的示例中的 when 子句。Note that the when clause in the example that attempts to test whether a Shape object is null doesn't execute. 测试是否为 null 的正确类型模式是 case null:The correct type pattern to test for a null is case null:.

C# 语言规范C# language specification

有关详细信息,请参阅 C# 语言规范中的 switch 语句For more information, see The switch statement in the C# Language Specification. 该语言规范是 C# 语法和用法的权威资料。The language specification is the definitive source for C# syntax and usage.

请参阅See also