Nota
O acesso a esta página requer autorização. Pode tentar iniciar sessão ou alterar os diretórios.
O acesso a esta página requer autorização. Pode tentar alterar os diretórios.
Declaração, constante e padrões
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#. Começa com a visão geral da correspondência de padrões se nunca usaste padrões C# antes. Para regras completas de linguagem, consulte a referência de padrões.
Um padrão é aplicado a uma expressão de entrada. C# avalia a expressão, depois o padrão testa ou captura o valor resultante. Os padrões de declaração, de constante e var respondem a três perguntas práticas:
- Padrão de declaração: A expressão produziu um valor não nulo de um tipo de execução compatível? Se sim, declare uma variável para esse valor.
- Padrão constante: A expressão produziu um valor constante específico?
-
varPadrão: Que valor teve a expressão? Captura-o sem antes testar o seu tipo ou valor.
Testar e capturar um tipo com um padrão de declaração
Um padrão de declaração consiste num tipo e numa designação. O tipo especifica que tipo de execução testar. A designação declara a variável que recebe o valor correspondente.
O exemplo seguinte recebe um object, pelo que a expressão pode produzir muitos tipos diferentes. O padrão de declaração permite que o ramo de correspondência utilize um valor decimal sem um teste de tipo separado e uma conversão:
static void PrintPrice(object value)
{
if (value is decimal amount)
{
Console.WriteLine($"Price: {amount:C}");
}
}
Em value is decimal amount:
-
valueé a expressão de entrada. C# avalia-o primeiro. -
decimalé o tipo testado. O padrão corresponde quando o valor avaliado não é nulo e o seu tipo de tempo de execução é compatível comdecimal. -
amounté a designação. Quando o padrão coincide, declaraamounte atribui-lhe o valor decimal.
O compilador acompanha se uma variável local recebe um valor antes do seu código o ler. Este acompanhamento chama-se atribuição definida. Dentro do bloco if, o compilador sabe que foi atribuído um valor a amount, porque o bloco só é executado quando o padrão corresponde. O compilador produz um erro se o seu código tentar aceder amount fora do if bloco. Se value não for um decimal valor, a variável amount não é atribuída a um valor.
Escolha um padrão de declaração quando o ramo correspondente precisar de usar o resultado como tipo testado. Combina o teste, a conversão e a declaração da variável, evitando assim repetir a expressão ou escrever um cast separado.
Também pode usar padrões de declaração quando uma expressão pode produzir vários tipos úteis:
static string FormatSensorValue(object reading) =>
reading switch
{
int count => $"Count: {count}",
double temperature => $"Temperature: {temperature:F1}°C",
string message => $"Message: {message}",
_ => "Unsupported reading"
};
Cada braço declara uma variável do tipo correspondente porque o resultado precisa do comportamento de formatação desse tipo. Um padrão de declaração corresponde apenas quando o valor avaliado não é nulo e já tem um tipo de execução compatível com o tipo testado através das conversões permitidas para padrões.
null não tem um tipo de tempo de execução para o padrão corresponder. O padrão também não executa operadores de conversão definidos pelo utilizador: é um teste e captura de tipos, não um pedido para converter o valor para outro tipo. Para as regras completas de compatibilidade, veja Padrões de Declaração e de tipos.
Corresponder a um valor específico com um padrão constante
Um padrão constante testa se uma expressão produz uma constante particular, como um número, cadeia, booleano, membro enum, valor declarado const , ou null.
Padrões constantes ajustam-se a uma expressão switch quando vários valores conhecidos produzem um resultado diferente:
static string GetCommandMessage(Command command) =>
command switch
{
Command.Start => "Starting",
Command.Stop => "Stopping",
Command.Pause => "Pausing",
_ => "Unknown command"
};
Command é um enum, um tipo que define um conjunto de constantes nomeadas.
Command.Start, Command.Stop, e Command.Pause são os seus membros enum, pelo que cada braço do switch usa um padrão constante para testar um valor de comando nomeado.
Escolha esta forma quando o comando pode ter vários significados distintos. Os braços do interruptor mantêm os valores e os seus resultados juntos. Para uma simples comparação de igualdade, uma if afirmação como if (command == Command.Start) é geralmente mais fácil de ler.
A correspondência de padrões constantes utiliza regras de igualdade de linguagem incorporadas em vez de um operador definido == pelo utilizador. Para as regras detalhadas de igualdade e conversão, veja a referência do padrão constante.
O null padrão constante é útil para uma verificação fiável do nulo:
static bool HasText(string? text) => text is not null;
Escolhe is null ou is not null quando estiveres a verificar o estado nulo. Estes padrões não chamam um operador de igualdade definido pelo utilizador, mesmo que o tipo da expressão sobrecarregue ==.
Captura um resultado para uma guarda com um var padrão
Um var padrão corresponde a todos os resultados, incluindo null, e declara uma variável cujo tipo é o tipo da expressão de entrada em tempo de compilação. Pode capturar um valor calculado enquanto outro padrão já está a corresponder a um objeto:
static string GetDeliveryMessage(object delivery) =>
delivery switch
{
ExpressDelivery express
when EstimateDays(express) is var days && days <= 2
=> $"Arrives in {days} day{(days == 1 ? "" : "s")}",
ExpressDelivery => "Express delivery for your location takes more than two days",
_ => "Standard delivery"
};
static int EstimateDays(ExpressDelivery delivery) =>
delivery.MilesAway <= 500 ? 1 :
delivery.MilesAway <= 1_000 ? 2 : 3;
record ExpressDelivery(int MilesAway);
O padrão ExpressDelivery express de declaração captura primeiro o objeto de entrega como express. A chamada ao método EstimateDays(express) é a expressão de entrada do padrão var. C# avalia essa chamada ao método e var days captura a estimativa resultante como days, sem testar o respetivo tipo nem valor. A estimativa pode ser de um ou dois dias quando a guarda tem sucesso. O resultado do arm precisa do valor capturado para indicar o número real de dias.
Uma variável local comum não pode ser declarada entre um padrão de ramo de switch e a sua when condição de guarda. Chamar EstimateDays(express) novamente no resultado repetiria o cálculo. Escolha esta var forma de padrão quando o código já estiver a corresponder, e tanto a guarda como o resultado precisam de um valor intermédio calculado.
Se não precisares do valor capturado, usa o padrão _de descarte em vez de declarar uma variável.