Descarte e padrão de descarte

Tip

Este artigo faz parte da secção Fundamentos para programadores que já conhecem pelo menos uma linguagem de programação e estão a aprender C#. Se és novo em padrões, começa pela visão geral da correspondência de moldes. Para sintaxe completa, veja a referência do padrão de descarte.

O token sublinhado (_) comunica que não é necessário um valor. O seu significado exato depende de onde aparece:

Context Significado de _
Um ramo de uma expressão switch ou um padrão aninhado Um padrão de descarte que corresponde sem capturar o resultado
Uma desconstrução ou um argumento out Um descarte que ignora um valor produzido
Uma tarefa como _ = expression Uma atribuição de descarte que avalia a expressão e ignora o seu resultado
Dois ou mais parâmetros lambda nomeados _ Descarte parâmetros cujas entradas não são usadas
var _ num padrão Um padrão com uma designação de ignorar var

Estes formulários partilham ortografia e intenção, mas não são intercambiáveis.

Correspondência de padrões com switch

No exemplo a seguir, statusCode é um int. Cada braço do interruptor produz uma string mensagem, que o programa escreve na consola. O final _ trata todos os códigos de estado exceto 200 e 404:

static void ShowStatus()
{
    int statusCode = 503;
    string message = statusCode switch
    {
        200 => "Ready",
        404 => "Not found",
        _ => "Another status"
    };

    Console.WriteLine(message);
}

Um padrão de descarte é aplicado a uma expressão de entrada. C# avalia a expressão e _ corresponde ao valor avaliado sem o capturar. Escolha _ como braço final de comutação de expressão quando todos os valores não tratados anteriormente devem usar o mesmo recurso. Coloca-o por último porque corresponde a tudo, incluindo null.

A forma var _ é um var padrão com designação de descarte. Também corresponde a todos os valores avaliados, mas não introduz uma variável legível. Prefira o padrão de descarte mais curto _ para um caso geral do switch. Para mais informações sobre var padrões e designações, veja Declaração, constante e var padrões.

Declarações de desestruturação

GetForecast devolve uma tupla com quatro componentes: uma string cidade e três int valores para a temperatura alta, temperatura baixa e probabilidade de chuva. A declaração de desconstrução mantém city e high porque o programa as mostra. Usa _ para a baixa temperatura e a probabilidade de chuva porque nomear esses componentes não usados implicaria que o código precisa deles:

static void ShowForecast()
{
    var (city, high, _, _) = GetForecast();
    Console.WriteLine($"{city}: high {high}°C");

    static (string City, int High, int Low, int RainChance) GetForecast() =>
        ("Portland", 18, 9, 40);
}

A mesma sintaxe de descarte funciona quando o método Deconstruct de um objeto produz vários valores. Para essas formas, veja Desconstruir tuplas e outros tipos.

Chamadas para métodos com out parâmetros

Suponha que um campo de entrada aceita texto apenas quando representa um número inteiro. O TryParse(String, Int32) método devolve um bool que informa se a análise sintática teve sucesso. Também produz o conteúdo analisado int através do parâmetro out. O seguinte código precisa apenas do resultado booleano para aceitar ou rejeitar a entrada:

static void CheckInput()
{
    string text = "42";

    if (IsWholeNumber(text))
    {
        Console.WriteLine($"Accepted: {text}");
    }
    else
    {
        Console.WriteLine("Enter a whole number.");
    }

    static bool IsWholeNumber(string text) => int.TryParse(text, out _);
}

Use out _ quando só o sucesso da operação importa. O descarte deixa claro que o número analisado não é necessário. Se um código posterior precisar do número, dá ao out argumento um nome, como out int number, e mantém esse valor em vez disso.

Uma atribuição de descarte, _ = expression, avalia uma expressão e ignora intencionalmente o seu resultado. É ocasionalmente útil quando a expressão não é uma afirmação válida.

Importante

Não uses _ = Task.Run(...) nem _ = SomeAsyncMethod() para descartar uma tarefa no código da aplicação. Aguarde a tarefa para que a sua conclusão e exceções permaneçam no fluxo de chamada. Uma atribuição de descarte não torna uma tarefa segura, não observa a sua exceção nem cria uma operação suportada de disparar e esquecer.

Marque parâmetros lambda não utilizados

Um EventHandler recebe um object? emissor e um EventArgs valor. O handler seguinte não necessita de nenhum parâmetro; apenas escreve "Timer tick" na consola. Nomear ambos os parâmetros _ torna o seu estado não utilizado visível sem inventar nomes que o corpo nunca utiliza:

static void ShowLambdaDiscards()
{
    EventHandler handler = (_, _) => Console.WriteLine("Timer tick");
    handler(null, EventArgs.Empty);
}

Escolha parâmetros de descarte quando uma assinatura de delegado requer entradas que o corpo lambda não utiliza. Se um lambda tiver apenas um parâmetro chamado _, _ mantém-se um nome comum de parâmetro para compatibilidade retroativa.

Evitar _ como identificador

_ pode ser um identificador comum em contextos onde C# não reconhece um descarte. Uma variável dentro do âmbito nomeada _ pode receber uma atribuição que se assemelha a uma atribuição de descarte. Num contexto de padrões, uma constante acessível ou tipo nomeado _ também pode alterar a forma como _ é interpretado. Evite declarar as suas próprias variáveis, constantes ou tipos nomeados _; use _ para comunicar a intenção de descarte.

Consulte também