switch (Referência em C#)switch (C# reference)

switch é uma instrução de seleção que escolhe uma única seção switch para ser executada de uma lista de candidatas com base em uma correspondência de padrão com a expressão de correspondência.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

A instrução switch geralmente é usada como uma alternativa para um constructo if-else se uma única expressão é testada com três ou mais condições.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. Por exemplo, a instrução switch a seguir determina se uma variável do tipo Color tem um dos três valores: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;   
      }
   }
}

Ela é equivalente ao exemplo a seguir que usa um constructo 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

A expressão de correspondênciaThe match expression

A expressão de correspondência fornece o valor para corresponder aos padrões nos rótulos case.The match expression provides the value to match against the patterns in case labels. A sintaxe é:Its syntax is:

   switch (expr)

No C# 6 e versões anteriores, a expressão de correspondência deve ser uma expressão que retorna um valor dos seguintes tipos:In C# 6 and earlier, the match expression must be an expression that returns a value of the following types:

Começando com o C# 7.0, a expressão de correspondência pode ser qualquer expressão não nula.Starting with C# 7.0, the match expression can be any non-null expression.

A seção switchThe switch section

Uma instrução switch inclui uma ou mais seções do comutador.A switch statement includes one or more switch sections. Cada seção switch contém um ou mais rótulos case (em um rótulo case ou padrão) seguidos por uma ou mais instruções.Each switch section contains one or more case labels (either a case or default label) followed by one or more statements. A instrução switch pode incluir no máximo um rótulo padrão colocado em qualquer seção switch.The switch statement may include at most one default label placed in any switch section. O exemplo a seguir mostra uma instrução switch simples que tem três seções switch, cada uma contendo duas instruções.The following example shows a simple switch statement that has three switch sections, each containing two statements. A segunda seção switch contém os rótulos case 2: e case 3:.The second switch section contains the case 2: and case 3: labels.

Uma instrução switch pode incluir qualquer número de seções switch e cada seção pode ter um ou mais rótulos case, conforme mostrado no exemplo a seguir.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. No entanto, dois rótulos case não podem conter a mesma expressão.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

Apenas uma seção switch em uma instrução switch é executada.Only one switch section in a switch statement executes. O C# não permite que a execução continue de uma seção switch para a próxima.C# doesn't allow execution to continue from one switch section to the next. Por isso, o código a seguir gera um erro do compilador, CS0163: "o controle não pode passar de um rótulo case (<rótulo case >) para outro".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;
}

Esse requisito é atendido normalmente saindo explicitamente da seção switch usando uma instrução break, goto ou return.This requirement is usually met by explicitly exiting the switch section by using a break, goto, or return statement. No entanto, o código a seguir também é válido porque garante que o controle do programa não pode passar para a seção 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)  
{
    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;                 
}  

A execução da lista de instruções na seção switch com um rótulo case que corresponde à expressão de correspondência começa com a primeira instrução e continua pela lista de instruções, normalmente até uma instrução de salto como break, goto case, goto label, return ou throw ser atingida.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. Nesse ponto, o controle é transferido para fora da instrução switch ou para outro rótulo case.At that point, control is transferred outside the switch statement or to another case label. Se uma instrução goto for usada, ela deverá transferir controle para um rótulo de constante.A goto statement, if it's used, must transfer control to a constant label. Essa restrição é necessária, já que tentar transferir o controle para um rótulo não constante pode ter efeitos colaterais indesejáveis, tais como transferência do controle para um local não intencional no código ou criação de um loop infinito.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.

Rótulos caseCase labels

Cada rótulo case especifica um padrão a ser comparado com a expressão de correspondência (a variável caseSwitch nos exemplos anteriores).Each case label specifies a pattern to compare to the match expression (the caseSwitch variable in the previous examples). Se eles corresponderem, o controle será transferido para a seção switch que contém o primeiro rótulo case correspondente.If they match, control is transferred to the switch section that contains the first matching case label. Se nenhum padrão de rótulo de caso corresponder à expressão de correspondência, o controle será transferido para a seção com o rótulo de caso default, se existir algum.If no case label pattern matches the match expression, control is transferred to the section with the default case label, if there's one. Se não houver nenhum case default, nenhuma declaração em qualquer seção switch será executada e o controle será transferido para fora da instrução switch.If there's no default case, no statements in any switch section are executed, and control is transferred outside the switch statement.

Para obter informações sobre a instrução switch e a correspondência de padrões, consulte a seção Correspondência de padrões com a instrução switch.For information on the switch statement and pattern matching, see the Pattern matching with the switch statement section.

Como o C# 6 dá suporte apenas ao padrão de constante e não permite a repetição de valores de constantes, os rótulos case definem valores mutuamente exclusivos e apenas um padrão pode corresponder à expressão de correspondência.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. Como resultado, a ordem na qual as instruções case aparecem não é importante.As a result, the order in which case statements appear is unimportant.

No entanto, no C# 7.0, como há suporte para outros padrões, os rótulos case não precisam definir valores mutuamente exclusivos e vários padrões podem corresponder à expressão de correspondência.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. Como são executadas apenas as instruções na primeira seção switch que contém o primeiro padrão de correspondência, a ordem na qual as instruções case aparecem agora é importante.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. Se o C# detecta uma seção switch cujas instruções case são equivalentes ou são subconjuntos de instruções anteriores, ele gera um erro do compilador, CS8120, “O switch case já foi tratado por um case anterior”.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."

O exemplo a seguir ilustra uma instrução switch que usa uma variedade de padrões não mutuamente exclusivos.The following example illustrates a switch statement that uses a variety of non-mutually exclusive patterns. Se você mover a seção switch case 0: para que ela não seja mais a primeira seção na instrução switch, o C# gera um erro do compilador porque um inteiro cujo valor é zero é um subconjunto de todos os inteiros, que é o padrão definido pela instrução 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>();
   }
}

Você pode corrigir esse problema e eliminar o aviso do compilador em uma das duas maneiras:You can correct this issue and eliminate the compiler warning in one of two ways:

  • Alterando a ordem das seções switch.By changing the order of the switch sections.

  • Usando uma cláusula where no rótulo case.By using a when clause in the case label.

O case defaultThe default case

O case default especifica a seção switch a ser executada se a expressão de correspondência não corresponder a nenhum outro rótulo case.The default case specifies the switch section to execute if the match expression doesn't match any other case label. Se um case default não estiver presente e a expressão de correspondência não corresponder a nenhum outro rótulo case, o fluxo do programa passará pela instrução 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.

O case default pode aparecer em qualquer ordem na instrução switch.The default case can appear in any order in the switch statement. Independentemente de sua ordem no código-fonte, ele é sempre avaliado por último, afinal os rótulos case foram avaliados.Regardless of its order in the source code, it's always evaluated last, after all case labels have been evaluated.

Correspondência de padrões com a instrução switch Pattern matching with the switch statement

Cada instrução case define um padrão que, se corresponde à expressão de correspondência, faz com que sua seção switch recipiente seja executada.Each case statement defines a pattern that, if it matches the match expression, causes its containing switch section to be executed. Todas as versões do C# dão suporte ao padrão de constante.All versions of C# support the constant pattern. Começando com o C# 7.0, há suporte para os padrões restantes.The remaining patterns are supported beginning with C# 7.0.

Padrão de constanteConstant pattern

O padrão de constante testa se a expressão de correspondência é igual a uma constante especificada.The constant pattern tests whether the match expression equals a specified constant. A sintaxe é:Its syntax is:

   case constant:

em que constant é o valor para testar.where constant is the value to test for. constant pode ser qualquer uma das expressões de constante a seguir:constant can be any of the following constant expressions:

  • Um literal bool, true ou false.A bool literal, either true or false.
  • Qualquer constante integral, como um int, um long ou um byte.Any integral constant, such as an int, a long, or a byte.
  • O nome de uma variável const declarada.The name of a declared const variable.
  • Uma constante de enumeração.An enumeration constant.
  • Um literal char.A char literal.
  • Um literal string.A string literal.

A expressão de constante é avaliada da seguinte forma:The constant expression is evaluated as follows:

  • Se expr e constant forem tipos integrais, o operador de igualdade de C# determinará se a expressão retorna true (ou seja, se expr == constant).If expr and constant are integral types, the C# equality operator determines whether the expression returns true (that is, whether expr == constant).

  • Caso contrário, o valor da expressão será determinado por uma chamada ao método estático Object.Equals(expr, constant).Otherwise, the value of the expression is determined by a call to the static Object.Equals(expr, constant) method.

O exemplo a seguir usa o padrão de constante para determinar se uma data específica é um final de semana, o primeiro dia, o último dia ou o meio da semana de trabalho.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. Ele avalia a propriedade DateTime.DayOfWeek do dia atual em relação aos membros da enumeração 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.

O exemplo a seguir usa o padrão de constante para manipular a entrada do usuário em um aplicativo de console que simula uma máquina de café automática.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.


Padrão de tipoType pattern

O padrão de tipo permite a conversão e a avaliação do tipo concisa.The type pattern enables concise type evaluation and conversion. Quando usado com a instrução switch para realizar a correspondência de padrões, testa se uma expressão pode ser convertida para um tipo especificado e, se puder, o converte em uma variável desse tipo.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. A sintaxe é:Its syntax is:

   case type varname

em que type é o nome do tipo no qual o resultado de expr deverá ser convertido e varname é o objeto para o qual o resultado de expr é convertido se a correspondência é bem-sucedida.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. O tipo de tempo de compilação expr pode ser um parâmetro de tipo genérico, começando com C# 7.1.The compile-time type of expr may be a generic type parameter, starting with C# 7.1.

A expressão case será true se qualquer uma das condições seguintes for verdadeira:The case expression is true if any of the following is true:

  • expr for uma instância do mesmo tipo que type.expr is an instance of the same type as type.

  • expr for uma instância de um tipo derivado de type.expr is an instance of a type that derives from type. Em outras palavras, o resultado de expr pode sofrer upcast para uma instância de type.In other words, the result of expr can be upcast to an instance of type.

  • expr tem um tipo de tempo de compilação que é uma classe base de type e expr tem um tipo de tempo de execução que é type ou é derivado de 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. O tipo do tempo de compilação de uma variável é o tipo da variável conforme definido em sua declaração de tipo.The compile-time type of a variable is the variable's type as defined in its type declaration. O tipo de tempo de execução de uma variável é o tipo da instância atribuída a essa variável.The runtime type of a variable is the type of the instance that is assigned to that variable.

  • expr é uma instância de um tipo que implementa a interface de type.expr is an instance of a type that implements the type interface.

Se a expressão case for true, varname será definitivamente atribuído e terá o escopo local dentro da seção switch apenas.If the case expression is true, varname is definitely assigned and has local scope within the switch section only.

Observe que null não corresponde a um tipo.Note that null doesn't match a type. Para corresponder um null, use o seguinte rótulo case:To match a null, you use the following case label:

case null:

O exemplo a seguir usa o padrão de tipo para fornecer informações sobre vários tipos de coleção.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

Em vez de object, você poderia empregar um método genérico, usando o tipo da coleção como o parâmetro de tipo, conforme mostrado no código a seguir: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.

A versão genérica é diferente da primeira amostra de duas maneiras.The generic version is different than the first sample in two ways. Primeiro, você não pode usar o case null.First, you can't use the null case. Você não pode usar nenhum case constante porque o compilador não pode converter qualquer tipo arbitrário de T para qualquer tipo diferente de object.You can't use any constant case because the compiler can't convert any arbitrary type T to any type other than object. O que tinha sido o case default agora testa para um object não nulo.What had been the default case now tests for a non-null object. Isso significa que o case default testa apenas para null.That means the default case tests only for null.

Sem a correspondência de padrões, esse código pode ser escrito da seguinte maneira.Without pattern matching, this code might be written as follows. O uso da correspondência de padrões de tipo produz um código mais compacto e legível eliminando a necessidade de testar se o resultado de uma conversão é um null ou executar conversões repetidas.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

A instrução case e a cláusula when The case statement and the when clause

A partir do C# 7.0, como as instruções case não precisam ser mutuamente exclusivas, você pode usar a adição de uma cláusula when para especificar uma condição adicional que precisa ser atendida para que a instrução case seja avaliada como 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. A cláusula when pode ser qualquer expressão que retorna um valor booliano.The when clause can be any expression that returns a Boolean value.

O exemplo a seguir define uma classe Shape base, uma classe Rectangle que deriva de Shape e uma classe Square que deriva de Rectangle.The following example defines a base Shape class, a Rectangle class that derives from Shape, and a Square class that derives from Rectangle. Ele usa a cláusula when para garantir que o ShowShapeInfo trata um objeto Rectangle que recebeu comprimentos e larguras como um Square mesmo se ele não tiver sido instanciado como um objeto 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. O método não tenta exibir informações sobre um objeto que é null ou uma forma cuja área é zero.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

Observe que a cláusula when no exemplo que tenta testar se um objeto Shape é null não é executada.Note that the when clause in the example that attempts to test whether a Shape object is null doesn't execute. O padrão de tipo correto para testar um null é case null:.The correct type pattern to test for a null is case null:.

Especificação da linguagem C#C# language specification

Para obter mais informações, consulte A instrução switch na Especificação da linguagem C#.For more information, see The switch statement in the C# Language Specification. A especificação da linguagem é a fonte definitiva para a sintaxe e o uso de C#.The language specification is the definitive source for C# syntax and usage.

Consulte tambémSee also