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.
Sugestão
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 de correspondência de moldes se os moldes forem novos para ti. Para regras completas da linguagem, veja padrões de propriedades e padrões posicionais na referência da linguagem.
Tanto os padrões de propriedades como os padrões posicionais testam partes de um valor. A diferença está na forma como identificam essas partes:
- Um padrão de propriedades nomeia as propriedades ou campos a testar.
- Um padrão posicional identifica valores pela sua ordem.
Uma desconstrução expõe um conjunto ordenado de valores de componentes. Uma tupla já tem uma ordem dos elementos; consulte desconstruir tuplas. Para outro tipo, um Deconstruct método define quais os valores dos componentes expostos e a sua ordem.
Comparar nomes e cargos
O seguinte padrão de propriedades 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 seguinte padrão posicional testa um valor de sinal seguido de um valor booleano:
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 propriedades identifica as suas entradas pelos nomes TemperatureC e HumidityPercent. O código de cruzamento cria um tuplo a partir dos valores separados signal e crossingIsClear. O padrão de tuplas identifica então esses valores por ordem: signal primeiro e crossingIsClear segundo. Um padrão posicional adequa-se bem, porque esta tupla acabada de criar tem apenas dois valores, e a sua ordem tem um significado claro na decisão de cruzar.
Escolha um padrão de propriedade quando os nomes dos membros ajudarem a explicar o teste. Os padrões de propriedades são geralmente mais claros para classes, estruturas e registos. 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 múltiplos valores relacionados num só valor com uma ordem fixa.
Seguir entradas aninhadas em padrões recursivos
Padrões de propriedades e posicionais são padrões recursivos: aplicam outro padrão a cada propriedade, corpo ou posição que selecionam. O valor selecionado torna-se o valor de entrada para esse padrão aninhado.
Em IsHotAndHumid, a reading expressão é a entrada para o padrão de propriedades. C# avalia essa expressão antes de combinar. 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 propriedades vazias corresponde a qualquer valor avaliado não nulo.
Os padrões de propriedades e posicionais correspondem apenas a valores avaliados não nulos. Quando null faz parte do domínio de entrada, escolha um padrão recursivo que verifique 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. C# avalia-o, e o { } padrão de propriedades testa o valor resultante para não-nulo antes de o atribuir a nonNullValue. A expressão de switch seguinte pode então testar múltiplos tipos possíveis de tempo de execução. Os seus padrões de tipo DateTime e string não têm designação porque o método só precisa de identificar cada tipo, não de captar o respetivo valor.
Quando as cláusulas de padrão recursivo contêm padrões aninhados, cada propriedade, campo ou posição selecionado torna-se a entrada para o seu padrão aninhado.
Pode adicionar um teste de tipo antes das órteses quando a expressão de entrada pode produzir diferentes tipos. 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. C# avalia-o primeiro e testa se o valor resultante é um DateTime. O valor da Date propriedade torna-se então a entrada para o acesso dos DayOfWeek membros. Finalmente, o DayOfWeek valor torna-se a entrada para o padrão lógico que testa duas constantes. A correspondência tem sucesso quando o valor externo tem o tipo especificado e todos os objetos necessários ao longo do caminho dos membros são não nulos.
Compare padrões com afirmações ramificadas
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 seguinte produz os mesmos resultados com uma série de instruções imperativas de ramificação:
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ões mantém os possíveis resultados juntos quando vários ramos testam o tipo e a forma de um valor. A versão imperativa torna explícito cada passo de teste e retorno. Numa condição, qualquer das formas pode ter um aspeto semelhante. À medida que o número de ramos relacionados cresce, os padrões podem tornar as alternativas mais fáceis de comparar.