switch (C# リファレンス)switch (C# reference)

switch ステートメントは選択ステートメントです。このステートメントは、実行する 1 つの "switch セクション" を候補のリストから "match 式" によるパターン マッチに基づいて選択します。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

switch ステートメントは、1 つの式が 3 つ以上の条件に対してテストされる場合に、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 型の変数に 3 つの値のいずれかが含まれているかどうかを確認します。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

match 式The match expression

match 式は、case ラベルのパターンと照合する値を指定します。The match expression provides the value to match against the patterns in case labels. 構文は次のとおりです。Its syntax is:

   switch (expr)

C# 6 以前では、match 式は、次の型の値を返す必要があります。In C# 6 and earlier, the match expression must be an expression that returns a value of the following types:

C# 7.0 以降は、match 式は NULL 以外の式にできます。Starting with C# 7.0, the match expression can be any non-null expression.

switch セクションThe switch section

switch ステートメントには、1 つ以上の switch セクションが含まれています。A switch statement includes one or more switch sections. 各 switch セクションには、1 つ以上の "case ラベル" (case ラベルまたは default ラベルのいずれか) と、その後に続く 1 つ以上のステートメントのリストが含まれています。Each switch section contains one or more case labels (either a case or default label) followed by one or more statements. switch ステートメントでは、任意の switch セクションに少なくとも 1 つの default ラベルを配置することができます。The switch statement may include at most one default label placed in any switch section. 次の例に、3 つの switch セクションを持つシンプルな switch ステートメントを示します。各セクションには 2 つのステートメントがあります。The following example shows a simple switch statement that has three switch sections, each containing two statements. 2 番目の switch セクションには、case 2: ラベルと case 3: ラベルが含められています。The second switch section contains the case 2: and case 3: labels.

switch ステートメントには、任意の数の switch セクションを含めることができます。また、次の例に示すように、各セクションに 1 つ以上の 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

1 つの switch ステートメントでは、1 つの switch セクションのみが実行されます。Only one switch section in a switch statement executes. C# では 1 つの switch セクションから次のセクションへ実行が連続することが許可されません。C# doesn't allow execution to continue from one switch section to the next. このため、次のコードでは、コンパイラ エラー CS0163:"コントロールは 1 つの 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;
}

この要件は、通常、break ステートメント、goto ステートメント、または return ステートメントを使用して、switch セクションを明示的に終了することによって満たされます。This requirement is usually met by explicitly exiting the switch section by using a break, goto, or return statement. ただし、次のコードも有効です。このコードでは、プログラムの制御が default switch セクションにフォール スルー (流れ落ちる、case ラベルを超えてコードを実行することが) できないためです。However, the following code is also valid, because it ensures that program control can't fall through to the default switch section.

switch (caseSwitch)  
{  
    // The following switch section causes an error.  
    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;                 
}  

match 式に一致する case ラベルが含まれた switch セクションにおけるステートメント リストの実行は、ステートメント リストに沿って最初のステートメントから順に開始され、通常は、breakgoto casegoto labelreturn、またはthrow などのジャンプ ステートメントに達するまで続きます。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 ステートメントを使用する場合は、制御を constant ラベルに転送する必要があります。A goto statement, if it's used, must transfer control to a constant label. この制約が必要になるのは、非 constant ラベルに制御を転送しようとすると望ましくない副作用 (コード内の意図しない場所に制御を転送してしまったり、無限ループを作成してしまったりなど) が生じる可能性があるためです。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 ラベルで、match 式と比較するためのパターンを指定します (前の例では caseSwitch 変数)。Each case label specifies a pattern to compare to the match expression (the caseSwitch variable in the previous examples). 一致すると、最初の一致 case を含む switch セクションに制御が移ります。If they match, control is transferred to the switch section that contains the first matching case label. match 式と一致する 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 ステートメントによるパターン マッチング」を参照してください。For information on the switch statement and pattern matching, see the Pattern matching with the switch statement section.

C# 6 でサポートされるのは定数パターンのみで、定数値の繰り返しは許可されません。このため、case ラベルでは相互に排他的な値が定義され、match 式と一致するのは 1 つのパターンだけです。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 ラベルで定義する値が相互に排他的である必要はなく、match 式と一致するパターンが複数存在する可能性があります。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. 一致するパターンを含む最初の switch セクションのステートメントのみが実行されるので、ここでは、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# によって switch セクションが検出され、その switch セクションの case ステートメントが前のステートメントと同じだったり、そのステートメントのサブセットだったりすると、コンパイラ エラー CS8120 "switch 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>();
   }
}

この問題を修正し、コンパイラの警告が表示されないようにするには、次の 2 つのいずれかの方法を使用します。You can correct this issue and eliminate the compiler warning in one of two ways:

  • switch セクションの順序を変更する。By changing the order of the switch sections.

  • case ラベルで when 句 を使用する。By using a when clause in the case label.

default caseThe default case

default case では、match 式がどの case ラベルとも一致しない場合に実行する switch セクションを指定します。The default case specifies the switch section to execute if the match expression doesn't match any other case label. default case を指定しない場合、match 式がどの 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 は、ソース コード内での順序に関係なく、すべての 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 ステートメントで定義されたパターンが match 式と一致した場合に、switch セクションが実行されます。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

定数パターンでは、match 式が、指定された定数と等しいかどうかがテストされます。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 リテラル。true または falseA bool literal, either true or false.
  • 任意の整数定数。intlongbyte など。Any integral constant, such as an int, a long, or a byte.
  • 宣言された const 変数の名前。The name of a declared const variable.
  • 列挙定数。An enumeration constant.
  • char リテラル。A char literal.
  • string リテラル。A string literal.

定数式は以下のように評価されます。The constant expression is evaluated as follows:

  • exprconstant が整数型の場合、式から true が返されるかどうか (つまり、expr == constant であるかどうか) が C# の等値演算子によって判定されます。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. つまり、現在の日付の DateTime.DayOfWeek プロパティを、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

ここで type は、expr の結果が変換される型の名前、varname は、一致した場合に expr の結果が変換されるオブジェクトを表しています。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. コンパイル時の型 expr は、C# 7.1 以降では、ジェネリック型パラメーターにすることができます。The compile-time type of expr may be a generic type parameter, starting with C# 7.1.

以下のいずれかの条件が true である場合に case 式は true となります。The case expression is true if any of the following is true:

  • exprtype と同じ型のインスタンスである。expr is an instance of the same type as type.

  • exprtype から派生した型のインスタンスである。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 が確実に割り当てられ、switch セクションにのみローカル スコープが含まれます。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.

ジェネリック バージョンは、2 つの点で最初のサンプルと異なります。The generic version is different than the first sample in two ways. まず、null の case を使用できません。First, you can't use the null case. コンパイラは任意の型 Tobject 以外の型に変換できないため、定数の case は使用できません。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 以外の object をテストするようになりました。What had been the default case now tests for a non-null object. つまり、default の case は null のみをテストします。That 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 句を使用して、同じ長さと幅が割り当てられている Rectangle オブジェクトが、Square オブジェクトとしてインスタンス化されていなくても、ShowShapeInfo によって確実に 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