Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Dica
Este artigo faz parte da seção Conceitos Básicos para desenvolvedores que já conhecem pelo menos uma linguagem de programação e estão aprendendo C#. Se você é novo em programação, comece com os tutoriais Comece agora. Desenvolvedores experientes em C# podem usar a referência de padrões para a sintaxe e as regras completas.
Vindo de outro idioma? Os padrões do C# desempenham um papel semelhante ao pattern matching do Java e aos casos de match do Python. O C# usa padrões em is expressões, switch instruções e switch expressões.
A correspondência de padrões aplica um padrão a uma expressão. Um padrão é uma condição para testar a expressão de entrada. A entrada padrão é essa expressão. O C# avalia a expressão de entrada; o resultado é o valor avaliado. O padrão testa se esse valor tem um tipo específico, é igual a um valor específico ou tem uma forma específica. Quando um padrão corresponde, seu código pode usar informações aprendidas pelo teste, como um tipo mais específico ou um valor extraído de um objeto.
Você pode usar um padrão em três contextos:
- No lado direito do operador
is. - Em um rótulo
casede uma instruçãoswitch. - Em um ramo de uma expressão
switch.
Os padrões testam uma entrada avaliada em relação a tipos, constantes ou uma forma que pode conter padrões aninhados. Uma condição booliana também pode comparar duas expressões avaliadas independentemente cujos valores não são constantes. Quando qualquer um dos formulários puder expressar o mesmo teste, escolha o formulário mais fácil de ler.
Por exemplo, o método a seguir usa uma switch expressão para escolher uma mensagem de entrega:
static string GetDeliveryMessage(Delivery? delivery) =>
delivery switch
{
null => "No delivery was scheduled.",
ExpressDelivery express => $"Express package {express.TrackingCode}",
StandardDelivery { Days: <= 2 } => "Standard delivery arriving soon",
_ => "Standard delivery"
};
Os padrões de propriedade podem incluir um teste de tipo externo e padrões aninhados, mas nenhum deles é necessário em todo padrão de propriedade. Em StandardDelivery { Days: <= 2 }, o padrão externo recebe a expressão delivery e testa o seu tipo. A expressão de propriedade Days passa então a ser a entrada do padrão relacional aninhado <= 2.
A expressão anterior switch é a expressão de entrada. Cada linha dentro das chaves é um braço de comutador. O padrão é exibido antes =>e o resultado aparece depois dele. O C# avalia a expressão de entrada e, em seguida, seleciona o primeiro ramo, na ordem do texto, cujo padrão corresponde e cuja guarda opcional when é true. A guarda opcional when é uma condição booleana adicional que é escrita após o padrão. O exemplo anterior mostrou os seguintes padrões:
-
nullé um padrão constante. Ele testa se adeliveryexpressão é avaliada comonull. -
ExpressDelivery expressé um padrão de declaração com duas partes.ExpressDeliveryé a parte de teste de tipo. Ele testa se o valor avaliado é um objeto não nulo cujo tipo de tempo de execução é compatível comExpressDelivery.expressé a designação de variável: ela declara uma variável nomeadaexpresse atribui o objeto correspondenteExpressDeliverya ela. -
StandardDelivery { Days: <= 2 }começa com um teste de tipo.StandardDeliverytesta se o valor avaliado é um objeto não nulo desse tipo. As chaves contêm um padrão de propriedade.Daysnomeia a propriedade a ser inspecionada, de modo que aDaysexpressão de propriedade se torna a entrada para o padrão recursivo. A<= 2parte é um padrão relacional, que testa se o valor avaliado é menor ou igual a2. -
_(sublinhado) é o padrão de descarte. Ele corresponde a todos os valores avaliados, incluindonull. Como os braços anteriores já tratam denull, entregas expressas e entregas padrão que chegam em até dois dias, este braço final trata de todos os valores restantes.
Um braço sem guarda when está desprotegido. Todos os braços no primeiro exemplo são desprotegidos. Se um braço anterior sem guarda corresponder a todos os valores avaliados aos quais um braço posterior poderia corresponder, o braço posterior estará subsumido. Um padrão subsumido é aquele em que todo valor de entrada possível que coincida com ele já tenha sido abrangido por um ramo anterior do switch. Isso nunca pode ser compatível, portanto o compilador gera um erro. O ramo de descarte (_) deve vir por último porque corresponde a todas as expressões de entrada. Um ramo protegido não engloba um ramo posterior com base apenas em seu padrão, porque a guarda pode ser false.
Uma expressão de comutador é exaustiva quando seus braços manipulam todas as expressões de entrada possíveis. O primeiro exemplo é exaustivo porque seu braço de descarte final manipula qualquer coisa que os braços anteriores não correspondam. O compilador avisa quando detecta um valor de entrada potencial que nenhum braço manipula. O compilador não pode provar a exaustividade para todas as combinações de padrões, mas este diagnóstico ajuda você a escrever código de correspondência de padrões correto. Para ver as regras detalhadas de correspondência, subsunção e exaustividade, consulte a referência de padrões.
Testar uma condição com is
Use o is operador quando precisar de um teste booliano. O código a seguir avalia a delivery expressão e aplica o padrão ExpressDelivery expressde declaração. A parte de tipo corresponde quando o valor avaliado não é nulo e seu tipo de tempo de execução é compatível com ExpressDelivery. Quando o padrão corresponde, sua designação de variável declara express:
static void PrintTrackingCode(Delivery delivery)
{
if (delivery is ExpressDelivery express)
{
Console.WriteLine($"Track express package {express.TrackingCode}");
}
}
O compilador controla se uma variável local foi atribuída antes de seu código lê-la. Esse rastreamento é chamado de atribuição definida. Dentro do bloco if, a condição só pode ser true quando o padrão atribui o objeto correspondente a express. O compilador, portanto, sabe que express é definitivamente atribuído lá. Seu código pode usar com segurança sua propriedade TrackingCode. Não é necessário um cast separado. Se você precisar apenas do teste de tipo e não precisar declarar uma variável, use um padrão de tipo, como delivery is ExpressDelivery.
Use is null ou is not null para verificações nulas. Esses padrões não chamam um operador != ou == definido pelo usuário.
static void PrintPackageStatus(Delivery? delivery)
{
if (delivery is null)
{
Console.WriteLine("No package is available.");
}
else
{
Console.WriteLine("A package is ready to track.");
}
}
Para obter mais diretrizes de segurança nula, consulte tipos de referência anuláveis.
Escolha entre uma instrução e uma expressão
Os padrões funcionam com ambas as formas de switch:
- Use uma
switchinstrução quando cada correspondência deve executar uma ou mais instruções. - Use uma
switchexpressão quando cada correspondência deve produzir um valor.
A instrução switch a seguir informa uma atualização sobre a entrega. O ramo de entrega expressa escreve duas mensagens, então uma declaração se encaixa naturalmente:
static void PrintDeliveryUpdate(Delivery? delivery)
{
switch (delivery)
{
case null:
Console.WriteLine("No delivery was scheduled.");
break;
case ExpressDelivery express:
Console.WriteLine($"Express delivery {express.TrackingCode} is ready.");
Console.WriteLine("Notify the priority desk.");
break;
case StandardDelivery standard:
Console.WriteLine($"Standard delivery arrives in {standard.Days} days.");
break;
default:
Console.WriteLine("Another delivery type is scheduled.");
break;
}
}
Cada expressão case aplica um padrão à expressão delivery. A seção correspondente pode executar qualquer número de instruções antes de break sair do switch. A seção default lida com qualquer coisa que os casos anteriores não correspondam.
A expressão de comutador a seguir substitui uma if / else if cadeia que atribui um resultado:
static string GetStatusMessage(StandardDelivery delivery) =>
delivery.Days switch
{
0 => "Delivered today",
1 => "Arriving tomorrow",
<= 3 => "Arriving soon",
_ => "In transit"
};
Uma expressão de comutador é concisa porque cada braço tem a mesma finalidade: produzir o valor retornado. Use uma instrução switch quando as ramificações executarem ações e use uma expressão switch quando as ramificações calcularem um único resultado.
Categorias de Padrões
O C# inclui padrões para tipos comuns de testes de dados:
| Categoria de padrão | O que ele testa |
|---|---|
Declarações, constantes e var padrões |
Um tipo de tempo de execução, um valor constante específico ou qualquer valor que você deseja capturar |
| Padrões de tipo | Um tipo de tempo de execução sem declarar uma variável |
| Padrões de propriedade e posicionais | Propriedades, campos ou valores desconstruídos |
| Padrões relacionais, lógicos e parênteses | Comparações e combinações, como and, ore not |
| Padrões de lista e fatiamento | Os valores e a forma de uma sequência suportada |
| Descartar padrões e itens descartados | Qualquer valor restante ou um valor que seu código ignora intencionalmente |
Os artigos de conceitos básicos vinculados explicam quando escolher cada categoria. Para obter sintaxe completa e exemplos, consulte a referência de padrões.