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#. Comece com a visão geral de correspondência de padrões se os padrões forem novos para você. Para obter regras de idioma completas, consulte padrões de propriedade e padrões posicionais na referência de idioma.
Padrões de propriedade e de posição testam partes de um valor. A diferença é como eles identificam essas partes:
- Um padrão de propriedade nomeia as propriedades ou os campos a serem testados.
- Um padrão posicional identifica valores por ordem.
Uma desconstrução expõe um conjunto ordenado de valores de componente. Uma tupla já tem uma ordem dos elementos; consulte desconstruir tuplas. Para outro tipo, um Deconstruct método define quais valores de componente são expostos e sua ordem.
Comparar nomes e posições
O padrão de propriedade a seguir testa duas propriedades nomeadas de uma leitura meteorológica, com valores de temperatura em graus Celsius:
static bool IsHotAndHumid(WeatherReading reading) =>
reading is { TemperatureC: > 30, HumidityPercent: > 70 };
sealed record WeatherReading(int TemperatureC, int HumidityPercent);
O padrão posicional a seguir testa um valor de sinal seguido por um valor booliano:
static string GetCrossingInstruction(
PedestrianSignal signal, bool crossingIsClear) =>
(signal, crossingIsClear) switch
{
(PedestrianSignal.Walk, true) => "Cross now",
(PedestrianSignal.Walk, false) => "Wait for the crossing to clear",
_ => "Wait for the walk signal"
};
enum PedestrianSignal
{
Stop,
Walk
}
O padrão de propriedade identifica suas entradas pelos nomes TemperatureC e HumidityPercent. O código de cruzamento cria uma tupla a partir dos valores separados crossingIsClear e signal. Em seguida, o padrão de tupla identifica esses valores por ordem: signal primeiro e crossingIsClear segundo. Um padrão posicional é uma ótima opção, porque essa tupla recém-criada tem apenas dois valores, e a ordem deles tem um significado claro na decisão sobre o cruzamento.
Escolha um padrão de propriedade quando os nomes dos membros ajudarem a explicar o teste. Os padrões de propriedade geralmente são mais claros para classes, structs e registros. Escolha um padrão posicional quando a ordem já dá aos valores um significado óbvio. Os padrões posicionais são mais úteis com tuplas, que combinam vários valores relacionados em um único valor, em uma ordem fixa.
Acompanhe entradas aninhadas em padrões recursivos
Padrões de propriedade e posicional são padrões recursivos: eles aplicam outro padrão a cada propriedade, campo ou posição selecionados. O valor selecionado se torna o valor de entrada desse padrão aninhado.
Em IsHotAndHumid, a expressão reading é a entrada do padrão de propriedade. O C# avalia essa expressão antes de fazer a correspondência de padrão. O padrão obtém dois valores do objeto resultante:
- O padrão
> 30relacional testa o valor deTemperatureC. - O padrão
> 70relacional testa o valor deHumidityPercent.
Um teste de tipo externo é opcional e as cláusulas de padrão recursivo podem estar vazias. Por exemplo, o padrão { } de propriedade vazio corresponde a qualquer valor avaliado não nulo.
Os padrões de propriedade e posicional correspondem apenas a valores avaliados não nulos. Quando null fizer parte do domínio de entrada, escolha um padrão recursivo que verifica primeiro um valor não nulo:
static string DescribeNullableInput(object? value)
{
if (value is not { } nonNullValue)
{
return "No value";
}
return nonNullValue switch
{
DateTime => "Date",
string => "Text",
_ => "Another type"
};
}
A expressão de entrada é value. O C# o avalia e o { } padrão de propriedade testa o valor resultante para não nulo antes de atribuí-lo a nonNullValue. A expressão de comutador a seguir pode testar vários tipos de runtime possíveis. Seus padrões de tipo string e DateTime não têm designador, porque o método só precisa identificar cada tipo, não capturar o valor.
Quando cláusulas de padrão recursivo contêm padrões aninhados, cada propriedade, campo ou posição selecionada se torna a entrada para seu padrão aninhado.
Você pode adicionar um teste de tipo antes das chaves quando a expressão de entrada pode produzir tipos diferentes. Você também pode usar um caminho de membro para testar uma propriedade aninhada:
static string DescribeDate(object? value) =>
value switch
{
DateTime { Date.DayOfWeek:
DayOfWeek.Saturday or DayOfWeek.Sunday } => "Weekend date",
DateTime => "Weekday date",
null => "No date",
_ => "Not a date"
};
value é a expressão de entrada. O C# primeiro o avalia e testa se o valor resultante é um DateTime. O valor da propriedade Date passa então a ser a entrada para o acesso ao membro DayOfWeek. Por fim, o DayOfWeek valor torna-se a entrada para o padrão lógico que testa duas constantes. A correspondência é bem-sucedida quando o valor externo tem o tipo especificado e cada objeto necessário ao longo do caminho do membro não é nulo.
Comparar padrões com instruções de ramificação
O método anterior DescribeDate expressa quatro resultados como padrões:
static string DescribeDate(object? value) =>
value switch
{
DateTime { Date.DayOfWeek:
DayOfWeek.Saturday or DayOfWeek.Sunday } => "Weekend date",
DateTime => "Weekday date",
null => "No date",
_ => "Not a date"
};
O método a seguir produz os mesmos resultados com uma série de instruções de ramificação imperativas:
static string DescribeDateWithBranches(object? value)
{
if (value is DateTime date)
{
if (date.DayOfWeek == DayOfWeek.Saturday ||
date.DayOfWeek == DayOfWeek.Sunday)
{
return "Weekend date";
}
return "Weekday date";
}
if (value is null)
{
return "No date";
}
return "Not a date";
}
A versão baseada em padrão mantém os resultados possíveis juntos quando várias ramificações testam o tipo e a forma de um valor. A versão imperativa torna cada etapa de teste e retorno explícita. Em uma condição, qualquer uma das formas pode parecer semelhante. À medida que o número de branches relacionados aumenta, os padrões podem facilitar a comparação das alternativas.