switch (Riferimenti per C#)switch (C# reference)

switch è un'istruzione di selezione che sceglie una sola sezione opzioni da eseguire da un elenco di candidati in base a un criterio di ricerca con l'espressione di ricerca.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

L'istruzione switch viene spesso usata come alternativa a un costrutto if-else se una singola espressione viene testata in base a tre o più condizioni.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. Ad esempio, l'istruzione switch determina se una variabile di tipo Color ha uno dei tre valori: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;   
      }
   }
}

È equivalente all'esempio seguente che usa un costrutto 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

Espressione di ricercaThe match expression

L'espressione di ricerca fornisce il valore da confrontare con i modelli nelle etichette case.The match expression provides the value to match against the patterns in case labels. La sintassi è la seguente:Its syntax is:

   switch (expr)

In C# 6 e versioni precedenti l'espressione di ricerca deve essere un'espressione che restituisce un valore dei tipi seguenti:In C# 6 and earlier, the match expression must be an expression that returns a value of the following types:

A partire da C# 7.0, l'espressione di ricerca può essere qualsiasi espressione non null.Starting with C# 7.0, the match expression can be any non-null expression.

Sezione opzioniThe switch section

Un'istruzione switch include una o più sezioni opzioni.A switch statement includes one or more switch sections. Ogni sezione switch contiene una o più etichette case (etichetta case o default) seguite da una o più istruzioni.Each switch section contains one or more case labels (either a case or default label) followed by one or more statements. L'istruzione switch può includere al massimo un'etichetta default posizionata in qualsiasi sezione switch.The switch statement may include at most one default label placed in any switch section. Nell'esempio seguente viene illustrata una semplice istruzione switch con tre sezioni switch, contenenti ognuna due istruzioni.The following example shows a simple switch statement that has three switch sections, each containing two statements. La seconda sezione switch contiene le etichette case 2: e case 3:.The second switch section contains the case 2: and case 3: labels.

Un'istruzione switch può contenere qualsiasi numero di sezioni opzioni e ogni sezione può avere una o più etichette case, come illustrato nell'esempio seguente.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. Tuttavia, due etichette case non possono contenere la stessa espressione.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

Viene eseguita una sola sezione opzioni in un'istruzione switch.Only one switch section in a switch statement executes. C# non consente di continuare l'esecuzione da una sezione opzioni a quella successiva.C# doesn't allow execution to continue from one switch section to the next. Per questo motivo, il codice seguente genera un errore di compilazione CS0163: "Il controllo non può passare da un'etichetta case (<case label>) a un'altra."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;
}

Questo requisito viene generalmente soddisfatto chiudendo in modo esplicito la sezione opzioni tramite un'istruzione break, goto o return.This requirement is usually met by explicitly exiting the switch section by using a break, goto, or return statement. Tuttavia, anche il codice seguente è valido, perché assicura che il controllo del programma non possa passare alla sezione opzioni 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;                 
}  

L'esecuzione dell'elenco di istruzioni nella sezione opzioni con un'etichetta case che corrisponde all'espressione di ricerca inizia con la prima istruzione e continua con l'elenco di istruzioni, in genere fino a raggiungere un'istruzione di salto, ad esempio 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. A quel punto, il controllo viene trasferito al di fuori dell'istruzione switch o in un'altra etichetta case.At that point, control is transferred outside the switch statement or to another case label. Un'istruzione goto, se usata, deve trasferire il controllo a un'etichetta costante.A goto statement, if it's used, must transfer control to a constant label. Questa restrizione è necessaria, perché il tentativo di trasferire il controllo a un'etichetta non costante può avere effetti collaterali indesiderati, come il trasferimento del controllo a una posizione non prevista nel codice o la creazione di un ciclo 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.

Etichette caseCase labels

Ogni etichetta case specifica un criterio da confrontare con l'espressione di ricerca (la variabile caseSwitch negli esempi precedenti).Each case label specifies a pattern to compare to the match expression (the caseSwitch variable in the previous examples). Se corrispondono, il controllo viene trasferito alla sezione opzioni che contiene la prima etichetta case corrispondente.If they match, control is transferred to the switch section that contains the first matching case label. Se nessun criterio di etichetta case corrisponde all'espressione di ricerca, il controllo viene trasferito alla sezione con etichetta case default, se presente.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 non è presente alcun case default, non vengono eseguite istruzioni in nessuna sezione opzioni e il controllo viene trasferito al di fuori dell'istruzione switch.If there's no default case, no statements in any switch section are executed, and control is transferred outside the switch statement.

Per informazioni sull'istruzione switch e sui criteri di ricerca, vedere Criteri di ricerca con la sezione switch istruzione.For information on the switch statement and pattern matching, see the Pattern matching with the switch statement section.

Poiché C# 6 supporta solo il criterio costante e non consente la ripetizione di valori costanti, le etichette case definiscono valori che si escludono a vicenda e solo un criterio può corrispondere all'espressione di ricerca.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. Di conseguenza, l'ordine in cui vengono visualizzate le istruzioni case non è rilevante.As a result, the order in which case statements appear is unimportant.

In C# 7.0, tuttavia, poiché sono supportati altri criteri, le etichette case non devono necessariamente definire valori che si escludono a vicenda e più criteri possono corrispondere all'espressione di ricerca.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. Dal momento che vengono eseguite solo le istruzioni nella prima sezione opzione che contiene il criterio di corrispondenza, l'ordine in cui ora vengono visualizzate le istruzioni case è 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 C# rileva una sezione opzioni la cui istruzione o istruzioni case sono equivalenti a o sono subset di istruzioni precedenti, viene generato l'errore del compilatore CS8120: "Lo switch case è già stato gestito da un case precedente."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."

Nell'esempio seguente viene illustrata un'istruzione switch che usa un'ampia gamma di criteri che non si escludono a vicenda.The following example illustrates a switch statement that uses a variety of non-mutually exclusive patterns. Se si sposta la sezione opzioni case 0: in modo che non sia più la prima sezione nell'istruzione switch, C# genera un errore del compilatore perché un numero intero il cui valore è uguale a zero è un sottoinsieme di tutti i numeri interi, che corrisponde al criterio definito dall'istruzione 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>();
   }
}

È possibile correggere il problema ed eliminare l'avviso del compilatore in uno dei due modi seguenti:You can correct this issue and eliminate the compiler warning in one of two ways:

  • Modificando l'ordine delle sezioni opzioni.By changing the order of the switch sections.

  • Usando una clausola when nell'etichetta case.By using a when clause in the case label.

Case defaultThe default case

Il case default specifica la sezione opzioni da eseguire se l'espressione di ricerca non corrisponde a nessun'altra etichetta case.The default case specifies the switch section to execute if the match expression doesn't match any other case label. Se non è presente un case default e l'espressione di ricerca non corrisponde a nessun'altra etichetta case, il flusso del programma salta l'istruzione 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.

Il case default può essere visualizzato in qualsiasi ordine nell'istruzione switch.The default case can appear in any order in the switch statement. Indipendentemente dall'ordine nel codice sorgente, viene sempre valutato per ultimo, dopo la valutazione di tutte le etichette case.Regardless of its order in the source code, it's always evaluated last, after all case labels have been evaluated.

Criteri di ricerca con istruzione switch Pattern matching with the switch statement

Ogni istruzione case definisce un criterio che, in caso di corrispondenza con l'espressione di ricerca, provoca l'esecuzione della sezione opzioni che la contiene.Each case statement defines a pattern that, if it matches the match expression, causes its containing switch section to be executed. Tutte le versioni di C# supportano il criterio costante.All versions of C# support the constant pattern. I criteri rimanenti sono supportati a partire da C# 7.0.The remaining patterns are supported beginning with C# 7.0.

Criterio costanteConstant pattern

Il criterio costante verifica se un'espressione di ricerca è uguale a una costante specificata.The constant pattern tests whether the match expression equals a specified constant. La sintassi è la seguente:Its syntax is:

   case constant:

dove costant è il valore su cui eseguire il test.where constant is the value to test for. constant può essere una delle espressioni costanti seguenti:constant can be any of the following constant expressions:

  • Un valore letterale bool, ad esempio true o false.A bool literal, either true or false.
  • Qualsiasi costante integrale, ad esempio un int, un long o un byte.Any integral constant, such as an int, a long, or a byte.
  • Il nome di una variabile const dichiarata.The name of a declared const variable.
  • Una costante di enumerazione.An enumeration constant.
  • Un valore letterale char.A char literal.
  • Un valore letterale string.A string literal.

L'espressione costante viene valutata nel modo seguente:The constant expression is evaluated as follows:

  • Se expr e constant sono tipi integrali, l'operatore di uguaglianza C# determina se l'espressione restituisce true (ovvero, 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).

  • In caso contrario, il valore dell'espressione è determinato da una chiamata al metodo Object.Equals(expr, constant) statico.Otherwise, the value of the expression is determined by a call to the static Object.Equals(expr, constant) method.

Nell'esempio seguente viene usato il modello costante per determinare se una determinata data è un fine settimana, il primo giorno della settimana lavorativa, l'ultimo giorno della settimana o nel mezzo della settimana lavorativa.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. Viene valutata la proprietà DateTime.DayOfWeek del giorno corrente con i membri dell'enumerazione 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.

L'esempio seguente usa il modello costante per gestire l'input dell'utente in un'applicazione console che simula una macchina per il caffè automatica.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.


Criterio del tipoType pattern

Il criterio del tipo consente la conversione e valutazione concise del tipo.The type pattern enables concise type evaluation and conversion. Quando si usa con l'espressione switch per eseguire i criteri di ricerca, verifica se un'espressione può essere convertita in un tipo specificato e, in tal caso, esegue il cast a una variabile di quel 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. La sintassi è la seguente:Its syntax is:

   case type varname

dove type è il nome del tipo in cui il risultato di expr deve essere convertito e varname è l'oggetto in cui il risultato di exprdeve essere convertito se la ricerca ha esito positivo.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. Il tipo in fase di compilazione di expr può essere un parametro di tipo generico, a partire da C# 7.1.The compile-time type of expr may be a generic type parameter, starting with C# 7.1.

L'espressione case è true se una delle condizioni seguenti è true:The case expression is true if any of the following is true:

  • expr è un'istanza dello stesso tipo di type.expr is an instance of the same type as type.

  • expr è un'istanza di un tipo che deriva da type.expr is an instance of a type that derives from type. In altre parole, il risultato di expr può subire l'upcast a un'istanza di type.In other words, the result of expr can be upcast to an instance of type.

  • expr ha un tipo in fase di compilazione che è una classe di base di type e expr ha un tipo di runtime che è type o è derivato da 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. Il tipo in fase di compilazione di una variabile è il tipo della variabile come definito nella relativa dichiarazione del tipo.The compile-time type of a variable is the variable's type as defined in its type declaration. Il tipo di runtime di una variabile è il tipo dell'istanza che viene assegnato alla variabile.The runtime type of a variable is the type of the instance that is assigned to that variable.

  • expr è un'istanza di un tipo che implementa l'interfaccia type.expr is an instance of a type that implements the type interface.

Se l'espressione del case è true, varname viene assegnata in modo definitivo e ha l'ambito locale esclusivamente all'interno della sezione opzioni.If the case expression is true, varname is definitely assigned and has local scope within the switch section only.

Si noti che null non corrisponde a un tipo.Note that null doesn't match a type. Per associare un null, usare l'etichetta case seguente:To match a null, you use the following case label:

case null:

Nell'esempio seguente viene usato il criterio del tipo per fornire informazioni sui vari generi di tipi di raccolta.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

Invece di object, si potrebbe creare un metodo generico usando il tipo della raccolta come parametro di tipo, come illustrato nel codice seguente: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 versione generica presenta due differenze rispetto al primo esempio.The generic version is different than the first sample in two ways. La prima è che non è possibile usare il case null.First, you can't use the null case. Non è possibile usare un case costante perché il compilatore non è in grado di convertire un tipo arbitrario T in alcun tipo diverso da object.You can't use any constant case because the compiler can't convert any arbitrary type T to any type other than object. Ciò che prima era il case default ora esegue il test per un object non Null.What had been the default case now tests for a non-null object. Questo significa che il case default esegue il test solo per null.That means the default case tests only for null.

Senza criteri di ricerca, questo codice potrebbe essere scritto come segue.Without pattern matching, this code might be written as follows. L'uso di criteri di ricerca del tipo produce codice più compatto e leggibile eliminando la necessità di verificare se il risultato di una conversione è un null o eseguire cast ripetuti.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

Istruzione case e clausola when The case statement and the when clause

A partire da C# 7.0, poiché le istruzioni case non devono escludersi a vicenda, è possibile aggiungere una clausola when per specificare una condizione aggiuntiva che deve essere soddisfatta perché l'istruzione case restituisca 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 clausola when può essere qualsiasi espressione che restituisce un valore booleano.The when clause can be any expression that returns a Boolean value.

Nell'esempio seguente viene definita una classe Shape di base, una classe Rectangle che deriva da Shape e una classe Square che deriva da Rectangle.The following example defines a base Shape class, a Rectangle class that derives from Shape, and a Square class that derives from Rectangle. L'esempio usa la clausola when per assicurarsi che ShowShapeInfo consideri un oggetto Rectangle a cui è stata assegnata pari lunghezza e larghezza di un elemento Square, anche nel caso in cui non sia stata creata un'istanza come oggetto 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. Il metodo non tenta di visualizzare informazioni su un oggetto null o su una forma la cui area è pari a 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

Si noti che la clausola when dell'esempio che tenta di verificare se un oggetto Shape è null non viene eseguita.Note that the when clause in the example that attempts to test whether a Shape object is null doesn't execute. Il criterio del tipo corretto da verificare per un null è case null:.The correct type pattern to test for a null is case null:.

Specifiche del linguaggio C#C# language specification

Per altre informazioni, vedere la sezione relativa all'istruzione switch nella specifica del linguaggio C#.For more information, see The switch statement in the C# Language Specification. La specifica del linguaggio costituisce il riferimento ufficiale principale per la sintassi e l'uso di C#.The language specification is the definitive source for C# syntax and usage.

Vedere ancheSee also