switch (справочник по C#)switch (C# reference)

switch — это оператор выбора, который выбирает для выполнения один раздел 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

Оператор 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.

Раздел switchThe switch section

Оператор switch включает один или несколько разделов 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 может включать не более одной метки default в каждом разделе switch.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 может содержать любое количество разделов 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 в операторе switch.Only one switch section in a switch statement executes. C# не позволяет продолжить выполнение следующего раздела switch после выполнения предыдущего.C# doesn't allow execution to continue from one switch section to the next. Поэтому, например, следующий код вызовет ошибку компиляции CS0163: "Управление не может передаваться вниз от одной метки case (<метка 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;
}

Обычно для соблюдения этого требования выполняется явный выход из раздела switch с использованием оператора break, goto или return.This requirement is usually met by explicitly exiting the switch section by using a break, goto, or return statement. При этом допустим также приведенный ниже код, так как он гарантирует, что управление программой не будет передано дальше, в раздел switch default.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;                 
}  

Выполнение списка операторов в разделе switch с меткой case, соответствующей выражению сопоставления, начинается с первого оператора и продолжается по списку, обычно до достижения оператора перехода, такого как break, goto case, goto label, return или 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, если он используется, должен передать управление константе типа метки.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.

Метки caseCase labels

Каждая метка case указывает на шаблон для сравнения с выражением сопоставления (переменная caseSwitch в предыдущем примере).Each case label specifies a pattern to compare to the match expression (the caseSwitch variable in the previous examples). Если они совпадают, управление передается разделу switch, который содержит первую соответствующую метку case.If they match, control is transferred to the switch section that contains the first matching case label. Если с выражением соответствия не совпадает ни один шаблон метки case, управление передается разделу с меткой case default при условии, что такой раздел существует.If no case label pattern matches the match expression, control is transferred to the section with the default case label, if there's one. Если метки case default нет, никакие операторы ни в одном из разделов 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 определяют взаимоисключающие значения. При этом выражению сопоставления может соответствовать только один шаблон.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. Поскольку в первом разделе 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. Обнаружив раздел switch, оператор или операторы которого эквивалентны предыдущим операторам или являются их подмножествами, C# выдает ошибку компилятора CS8120, "Метка case оператора 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. Если раздел switch case 0: перемещается и перестает быть первым разделом в операторе 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:

  • изменив порядок разделов switch;By changing the order of the switch sections.

  • используя предложение when в метке case.By using a when clause in the case label.

Метка case defaultThe default case

Метка case default указывает на раздел switch, который будет выполнен, если выражение соответствия не совпадет ни с одной другой меткой case.The default case specifies the switch section to execute if the match expression doesn't match any other case label. Если метки case default нет, а выражение соответствия не совпадает ни с одной другой меткой 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.

Метка case default может отображаться в операторе 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 определяет шаблон, который в случае совпадения с выражением соответствия вызывает выполнение входящего в него раздела 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

Шаблон константы проверяет, равно ли выражение указанной константе.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 или false;A bool literal, either true or false.
  • любой целочисленный тип, такой как int, long или byte;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:

  • Если expr и constant являются целочисленными типами, оператор равенства 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. Он сравнивает свойство 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. Начиная с C# 7.1 тип времени компиляции у expr может быть параметром универсального типа.The compile-time type of expr may be a generic type parameter, starting with C# 7.1.

Выражение case имеет значение true, если выполняется одно из следующих условий:The 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 присваивается определенным образом и получает локальную область в пределах раздела 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.

У универсальной версии есть два отличия от первого примера.The generic version is different than the first sample in two ways. Во-первых, нельзя использовать case null.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. Прежний оператор case default теперь выполняет проверку object на значения, не равные NULL.What had been the default case now tests for a non-null object. Это означает, что case default выполняет проверку только на 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, класс Rectangle, производный от Shape, и класс Square, производный от Rectangle.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

Обратите внимание на то, что предложение when в этом примере, проверяющее, имеет ли объект Shape значение null, не выполняется.Note that the when clause in the example that attempts to test whether a Shape object is null doesn't execute. Правильный шаблон пути для проверки на наличие значения nullcase null:.The correct type pattern to test for a null is case null:.

Спецификация языка C#C# language specification

Дополнительные сведения см. в разделе Оператор switch в статье Спецификации языка C#.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