switch (referencia de C#)switch (C# reference)

switch es una instrucción de selección que elige una sola sección switch para ejecutarla desde una lista de candidatos en función de una coincidencia de patrones con la expresión de coincidencia.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

La instrucción switch se suele usar como alternativa a un constructor if-else si una sola expresión se prueba con tres o más condiciones.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 ejemplo, la siguiente instrucción switch determina si una variable de tipo Color tiene uno de tres 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;   
      }
   }
}

Es equivalente al siguiente ejemplo que usa un constructor 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

Expresión de coincidenciaThe match expression

La expresión de coincidencia proporciona el valor que debe coincidir con los patrones de las etiquetas case.The match expression provides the value to match against the patterns in case labels. Su sintaxis es:Its syntax is:

   switch (expr)

En C# 6 y versiones anteriores, la expresión de coincidencia debe ser una expresión que devuelva un valor de los siguientes tipos:In C# 6 and earlier, the match expression must be an expression that returns a value of the following types:

A partir de C# 7.0, la expresión de coincidencia puede ser cualquier expresión que no sea nula.Starting with C# 7.0, the match expression can be any non-null expression.

Sección switchThe switch section

Una instrucción switch incluye una o más secciones switch.A switch statement includes one or more switch sections. Cada sección switch contiene una o más etiquetas case (ya sea una etiqueta case o default) seguidas de una o más instrucciones.Each switch section contains one or more case labels (either a case or default label) followed by one or more statements. La instrucción switch puede incluir como máximo una etiqueta default colocada en cualquier sección switch.The switch statement may include at most one default label placed in any switch section. En el ejemplo siguiente se muestra una instrucción switch simple con tres secciones switch, cada una de ellas contiene dos instrucciones.The following example shows a simple switch statement that has three switch sections, each containing two statements. La segunda sección switch contiene las etiquetas case 2: y case 3:.The second switch section contains the case 2: and case 3: labels.

Una instrucción switch puede incluir cualquier número de secciones switch y cada sección puede tener una o más etiquetas case, como se muestra en el ejemplo siguiente.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. Pero dos etiquetas case no pueden contener la misma expresión.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

Solo se ejecuta una sección switch en una instrucción switch.Only one switch section in a switch statement executes. C# no permite que la ejecución continúe de una sección switch a la siguiente.C# doesn't allow execution to continue from one switch section to the next. Por eso, el código siguiente genera un error del compilador, CS0163: "El control no puede pasar explícitamente de una etiqueta de caso (<etiqueta de caso>) a otra".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;
}

Este requisito se suele cumplir al salir explícitamente de la sección switch mediante una instrucción break, goto o return.This requirement is usually met by explicitly exiting the switch section by using a break, goto, or return statement. Pero el código siguiente también es válido, porque garantiza que el control del programa no puede pasar explícitamente a la sección 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;                 
}  

La ejecución de la lista de instrucciones en la sección switch con una etiqueta case que coincide con la expresión de coincidencia comienza con la primera instrucción y continúa a lo largo de la lista de instrucciones, normalmente hasta que se alcanza una instrucción de salto, como break, goto case, goto label, return o 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. En este punto, el control se transfiere fuera de la instrucción switch o a otra etiqueta case.At that point, control is transferred outside the switch statement or to another case label. Una instrucción goto, si se usa, debe transferir el control a una etiqueta de constante.A goto statement, if it's used, must transfer control to a constant label. Esta restricción es necesaria, ya que el intento de transferir el control a una etiqueta que no es de constante puede tener efectos secundarios no deseados, como la transferencia de control a una ubicación no deseada en el código o la creación de un bucle sin fin.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.

Etiquetas caseCase labels

Cada etiqueta case especifica un patrón que se compara con la expresión de coincidencia (la variable caseSwitch en los ejemplos anteriores).Each case label specifies a pattern to compare to the match expression (the caseSwitch variable in the previous examples). Si coinciden, el control se transfiere a la sección switch que contiene la primera etiqueta case coincidente.If they match, control is transferred to the switch section that contains the first matching case label. Si ningún patrón de etiqueta case coincide con la expresión de coincidencia, el control se transfiere a la sección con la etiqueta case default, si la hubiera.If no case label pattern matches the match expression, control is transferred to the section with the default case label, if there's one. Si no hay ninguna etiqueta case default, no se ejecuta ninguna instrucción de ninguna sección switch y el control se transfiere fuera de la instrucción switch.If there's no default case, no statements in any switch section are executed, and control is transferred outside the switch statement.

Para más información sobre la instrucción switch y la coincidencia de patrones, vea la sección Coincidencia de patrones con la instrucción switch.For information on the switch statement and pattern matching, see the Pattern matching with the switch statement section.

Dado que C# 6 solo admite el patrón constante y no permite la repetición de valores constantes, las etiquetas case definen valores mutuamente exclusivos y solo un patrón puede coincidir con la expresión de coincidencia.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. Por este motivo, el orden en que aparezcan las instrucciones case no tiene importancia.As a result, the order in which case statements appear is unimportant.

Pero en C# 7.0, dado que se admiten otros patrones, las etiquetas de caso no necesitan definir valores mutuamente exclusivos y varios patrones pueden coincidir con la expresión de coincidencia.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. Puesto que solo se ejecutan las instrucciones de la primera sección switch que contiene el patrón coincidente, el orden en que aparecen las instrucciones case sí es 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. Si C# detecta una sección switch cuya instrucción o instrucciones case son equivalentes a o son subconjuntos de instrucciones anteriores, genera un error del compilador, CS8120: "El caso del modificador ya se ha gestionado en un caso 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."

En el ejemplo siguiente se muestra una instrucción switch que usa una variedad de patrones que no son mutuamente excluyentes.The following example illustrates a switch statement that uses a variety of non-mutually exclusive patterns. Si mueve la sección switch case 0: de modo que ya no sea la primera sección de la instrucción switch, C# genera un error del compilador debido a que un entero cuyo valor es cero es un subconjunto de todos los enteros, que es el patrón definido por la instrucción 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>();
   }
}

Puede corregir este problema y eliminar la advertencia del compilador de alguna de estas dos formas:You can correct this issue and eliminate the compiler warning in one of two ways:

  • Si cambia el orden de las secciones switch.By changing the order of the switch sections.

  • Si usa una cláusula when en la etiqueta case.By using a when clause in the case label.

Etiqueta case defaultThe default case

La etiqueta case default especifica la sección switch que se va a ejecutar si la expresión de coincidencia no coincide con ninguna otra etiqueta case.The default case specifies the switch section to execute if the match expression doesn't match any other case label. Si no hay ninguna etiqueta case default y la expresión de coincidencia no coincide con ninguna otra etiqueta case, el flujo del programa pasa a la instrucción 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.

La etiqueta case default puede aparecer en cualquier orden en la instrucción switch.The default case can appear in any order in the switch statement. Independientemente de su orden en el código fuente, siempre se evalúa en último lugar, después de que se hayan evaluado las demás etiquetas case.Regardless of its order in the source code, it's always evaluated last, after all case labels have been evaluated.

Coincidencia de patrones con la instrucción switch Pattern matching with the switch statement

Cada instrucción case define un patrón que, si coincide con la expresión de coincidencia, provoca la ejecución de su sección switch contenedora.Each case statement defines a pattern that, if it matches the match expression, causes its containing switch section to be executed. Todas las versiones de C# admiten el patrón de constante.All versions of C# support the constant pattern. Los demás patrones se admiten a partir de C# 7.0.The remaining patterns are supported beginning with C# 7.0.

Patrón de constanteConstant pattern

El patrón de constante comprueba si la expresión de coincidencia es igual a una constante especificada.The constant pattern tests whether the match expression equals a specified constant. Su sintaxis es:Its syntax is:

   case constant:

donde constant es el valor que se va a comprobar.where constant is the value to test for. constant puede ser cualquiera de las expresiones de constante siguientes:constant can be any of the following constant expressions:

  • Un literal booleano, ya sea true o false.A bool literal, either true or false.
  • Cualquier constante entera, como int, long o byte.Any integral constant, such as an int, a long, or a byte.
  • El nombre de una variable const declarada.The name of a declared const variable.
  • Una constante de enumeración.An enumeration constant.
  • Un literal de carácter.A char literal.
  • Un literal de cadena.A string literal.

La expresión de constante se evalúa de la siguiente forma:The constant expression is evaluated as follows:

  • Si expr y constant son tipos enteros, el operador de igualdad de C# determina si la expresión devuelve true (es decir, si expr == constant).If expr and constant are integral types, the C# equality operator determines whether the expression returns true (that is, whether expr == constant).

  • De lo contrario, el valor de la expresión se determina mediante una llamada al 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.

En el ejemplo siguiente se usa el patrón de constante para determinar si una fecha determinada es un fin de semana, el primer día, el último día o la mitad de la semana laboral.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. Evalúa la propiedad DateTime.DayOfWeek del día actual con los miembros de la enumeración 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.

En el ejemplo siguiente se usa el patrón de constante para controlar la entrada del usuario en una aplicación de consola que simula una cafetera 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.


Patrón de tipoType pattern

El patrón de tipo habilita la conversión y la evaluación de tipo concisas.The type pattern enables concise type evaluation and conversion. Cuando se usa con la instrucción switch para realizar la coincidencia de patrones, comprueba si una expresión se puede convertir en un tipo especificado y, en caso afirmativo, la convierte en una variable de ese 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. Su sintaxis es:Its syntax is:

   case type varname

donde type es el nombre del tipo al que se va a convertir el resultado de expr y varname es el objeto al que se va a convertir el resultado de expr si hay coincidencia.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. El tipo de tiempo de compilación de expr puede ser un parámetro de tipo genérico a partir de C# 7.1.The compile-time type of expr may be a generic type parameter, starting with C# 7.1.

La expresión case es true si se cumple alguna de las siguientes condiciones:The case expression is true if any of the following is true:

  • expr es una instancia del mismo tipo que type.expr is an instance of the same type as type.

  • expr es una instancia de un tipo que deriva de type.expr is an instance of a type that derives from type. En otras palabras, el resultado de expr puede convertirse en una instancia de type.In other words, the result of expr can be upcast to an instance of type.

  • expr tiene un tipo en tiempo de compilación que es una clase base de type y expr tiene un tipo en tiempo de ejecución que es type o se deriva 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. El tipo en tiempo de compilación de una variable es el tipo de la variable tal como se define en su declaración de tipos.The compile-time type of a variable is the variable's type as defined in its type declaration. El tipo en tiempo de ejecución de una variable es el tipo de la instancia que se asigna a esa variable.The runtime type of a variable is the type of the instance that is assigned to that variable.

  • type es una instancia de un tipo que implementa la interfaz type.expr is an instance of a type that implements the type interface.

Si la expresión case es true, varname se asigna definitivamente y tiene ámbito local únicamente dentro de la sección switch.If the case expression is true, varname is definitely assigned and has local scope within the switch section only.

Tenga en cuenta que null no coincide con un tipo.Note that null doesn't match a type. Para que null coincida, use la siguiente etiqueta case:To match a null, you use the following case label:

case null:

En el ejemplo siguiente se usa el patrón de tipo para proporcionar información sobre los distintos tipos de colección.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

En lugar de object, podría crear un método genérico, con el tipo de la colección como el parámetro de tipo, tal como se muestra en el código siguiente: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.

La versión genérica es distinta del primer ejemplo de dos maneras.The generic version is different than the first sample in two ways. En primer lugar, no puede usar el caso null.First, you can't use the null case. No puede usar ningún caso constante porque el compilador no puede convertir ningún tipo arbitrario T a ningún tipo distinto 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. Lo que habría sido el caso default ahora se prueba para un object no nulo.What had been the default case now tests for a non-null object. Esto significa que el caso default solo se prueba para null.That means the default case tests only for null.

Sin coincidencia de patrones, este código podría escribirse del modo siguiente.Without pattern matching, this code might be written as follows. El uso de la coincidencia de patrones de tipo genera código más compacto y legible al eliminar la necesidad de comprobar si el resultado de una conversión es null o de realizar conversiones 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

La instrucción case y la cláusula when The case statement and the when clause

A partir de C# 7.0, dado que las instrucciones case no necesitan ser mutuamente excluyentes, puede agregar una cláusula when para especificar una condición adicional que deba cumplirse para que la instrucción case se evalúe 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. La cláusula when puede ser cualquier expresión que devuelva un valor booleano.The when clause can be any expression that returns a Boolean value.

En el ejemplo siguiente se define una clase base Shape, una clase Rectangle que deriva de Shape y una clase 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. Usa la cláusula when para asegurarse de que ShowShapeInfo trate a un objeto Rectangle al que se han asignado las mismas longitudes y anchos como si fuera Square aunque de él no se hayan creado instancias como de un 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. El método no intenta mostrar información sobre un objeto que es null ni sobre una forma cuya área es cero.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

Tenga en cuenta que la cláusula when del ejemplo que intenta comprobar si un objeto Shape es null no se ejecuta.Note that the when clause in the example that attempts to test whether a Shape object is null doesn't execute. El patrón de tipo correcto para comprobar null es case null:.The correct type pattern to test for a null is case null:.

Especificación del lenguaje C#C# language specification

Para obtener más información, vea el apartado Instrucción switch en Especificación del lenguaje C#.For more information, see The switch statement in the C# Language Specification. La especificación del lenguaje es la fuente definitiva de la sintaxis y el uso de C#.The language specification is the definitive source for C# syntax and usage.

Vea tambiénSee also