expressão switch (referência C#)switch expression (C# reference)

Este artigo aborda a switch expressão, introduzida em C# 8,0.This article covers the switch expression, introduced in C# 8.0. Para obter informações sobre switch a instrução, consulte o artigo sobre a switch instrução na seção de instruções .For information on the switch statement, see the article on the switch statement in the statements section.

Exemplo básicoBasic example

A switch expressão fornece switchsemântica semelhante em um contexto de expressão.The switch expression provides for switch-like semantics in an expression context. Ele fornece uma sintaxe concisa quando os braços de switch produzem um valor.It provides a concise syntax when the switch arms produce a value. O exemplo a seguir mostra a estrutura de uma expressão switch.The following example shows the structure of a switch expression. Ele traduz valores de uma enum representação de direções visuais em um mapa online para a direção Cardeal correspondente:It translates values from an enum representing visual directions in an online map to the corresponding cardinal direction:

public static class SwitchExample
{
    public enum Directions
    {
        Up,
        Down,
        Right,
        Left
    }

    public enum Orientation
    {
        North,
        South,
        East,
        West
    }

    public static void Main()
    {
        var direction = Directions.Right;
        Console.WriteLine($"Map view direction is {direction}");

        var orientation = direction switch
        {
            Directions.Up    => Orientation.North,
            Directions.Right => Orientation.East,
            Directions.Down  => Orientation.South,
            Directions.Left  => Orientation.West,
        };
        Console.WriteLine($"Cardinal orientation is {orientation}");
    }
}

O exemplo anterior mostra os elementos básicos de uma expressão switch:The preceding sample shows the basic elements of a switch expression:

  • A expressão de intervalo: o exemplo anterior usa a direction variável como a expressão de intervalo.The range expression: The preceding example uses the variable direction as the range expression.
  • Os braços de expressão switch: cada ARM de expressão switch contém um padrão, uma proteção de casoopcional, o => token e uma expressão.The switch expression arms: Each switch expression arm contains a pattern, an optional case guard, the => token, and an expression.

O resultado da expressão switch é o valor da expressão do primeiro ARM de expressão switch cujo padrão corresponde à expressão Range e cujo Case Guard, se presente, é avaliado como true.The result of the switch expression is the value of the expression of the first switch expression arm whose pattern matches the range expression and whose case guard, if present, evaluates to true. A expressão à direita do => token não pode ser uma instrução de expressão.The expression on the right of the => token can't be an expression statement.

Os braços de expressão switch são avaliados em ordem de texto.The switch expression arms are evaluated in text order. O compilador emite um erro quando um ARM de expressão de comutador inferior não pode ser escolhido porque um ARM de expressão de comutador superior corresponde a todos os seus valores.The compiler issues an error when a lower switch expression arm can't be chosen because a higher switch expression arm matches all its values.

Padrões e proteções de casoPatterns and case guards

Muitos padrões têm suporte em braços de expressão de switch.Many patterns are supported in switch expression arms. O exemplo anterior usou um padrão de valor.The preceding example used a value pattern. Um padrão de valor compara a expressão de intervalo com um valor.A value pattern compares the range expression to a value. Esse valor deve ser uma constante de tempo de compilação.That value must be a compile time constant. O padrão de tipo compara a expressão de intervalo com um tipo conhecido.The type pattern compares the range expression to a known type. O exemplo a seguir recupera o terceiro elemento de uma sequência.The following example retrieves the third element from a sequence. Ele usa métodos diferentes com base no tipo da sequência:It uses different methods based on the type of the sequence:

public static T TypeExample<T>(IEnumerable<T> sequence) =>
    sequence switch
    {
        System.Array array => (T)array.GetValue(2),
        IList<T> list      => list[2],
        IEnumerable<T> seq => seq.Skip(2).First(),
    };

Os padrões podem ser recursivos, onde um padrão testa um tipo e, se esse tipo corresponder, o padrão corresponde a um ou mais valores de propriedade na expressão de intervalo.Patterns can be recursive, where a pattern tests a type, and if that type matches, the pattern matches one or more property values on the range expression. Você pode usar padrões recursivos para estender o exemplo anterior.You can use recursive patterns to extend the preceding example. Você adiciona braços de expressão de switch para matrizes com menos de três elementos.You add switch expression arms for arrays that have fewer than 3 elements. Padrões recursivos são mostrados no exemplo a seguir:Recursive patterns are shown in the following example:

public static T RecursiveExample<T>(IEnumerable<T> sequence) =>
    sequence switch
    {
        System.Array { Length : 0}       => default(T),
        System.Array { Length : 1} array => (T)array.GetValue(0),
        System.Array { Length : 2} array => (T)array.GetValue(1),
        System.Array array               => (T)array.GetValue(2),
        IList<T> list                    => list[2],
        IEnumerable<T> seq               => seq.Skip(2).First(),
    };

Padrões recursivos podem examinar as propriedades da expressão de intervalo, mas não podem executar código arbitrário.Recursive patterns can examine properties of the range expression, but can't execute arbitrary code. Você pode usar um protetor de caso, especificado em when uma cláusula, para fornecer verificações semelhantes para outros tipos de sequência:You can use a case guard, specified in a when clause, to provide similar checks for other sequence types:

public static T CaseGuardExample<T>(IEnumerable<T> sequence) =>
    sequence switch
    {
        System.Array { Length : 0}                => default(T),
        System.Array { Length : 1} array          => (T)array.GetValue(0),
        System.Array { Length : 2} array          => (T)array.GetValue(1),
        System.Array array                        => (T)array.GetValue(2),
        IEnumerable<T> list when !list.Any()      => default(T),
        IEnumerable<T> list when list.Count() < 3 => list.Last(),
        IList<T> list                             => list[2],
        IEnumerable<T> seq                        => seq.Skip(2).First(),
    };

Por fim, você pode adicionar _ o padrão e null o padrão para capturar argumentos que não são processados por nenhum outro ARM de expressão de switch.Finally, you can add the _ pattern and the null pattern to catch arguments that aren't processed by any other switch expression arm. Isso torna a expressão de comutador exaustiva, o que significa que qualquer valor possível da expressão de intervalo é manipulado.That makes the switch expression exhaustive, meaning any possible value of the range expression is handled. O exemplo a seguir adiciona esses braços de expressão:The following example adds those expression arms:

public static T ExhaustiveExample<T>(IEnumerable<T> sequence) =>
    sequence switch
    {
        System.Array { Length : 0}       => default(T),
        System.Array { Length : 1} array => (T)array.GetValue(0),
        System.Array { Length : 2} array => (T)array.GetValue(1),
        System.Array array               => (T)array.GetValue(2),
        IEnumerable<T> list
            when !list.Any()             => default(T),
        IEnumerable<T> list
            when list.Count() < 3        => list.Last(),
        IList<T> list                    => list[2],
        null                             => throw new ArgumentNullException(nameof(sequence)),
        _                                => sequence.Skip(2).First(),
    };

O exemplo anterior adiciona um null padrão e altera o IEnumerable<T> padrão de tipo para um _ padrão.The preceding example adds a null pattern, and changes the IEnumerable<T> type pattern to a _ pattern. O null padrão fornece uma verificação nula como um ARM de expressão switch.The null pattern provides a null check as a switch expression arm. A expressão para esse ARM gera um ArgumentNullException.The expression for that arm throws an ArgumentNullException. O _ padrão corresponde a todas as entradas que não corresponderam aos braços anteriores.The _ pattern matches all inputs that haven't been matched by previous arms. Ele deve vir após a null verificação, ou ele corresponderá null a entradas.It must come after the null check, or it would match null inputs.

Você pode ler mais na proposta de especificação da linguagem C# para obter padrões recursivos.You can read more in the C# language spec proposal for recursive patterns.

Veja tambémSee also