Padrões de lista e corte

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 de tipo e linguagem suportadas, consulte padrões de lista na referência da linguagem.

A forma de uma sequência é o conjunto de propriedades observáveis que um padrão exige. Estas propriedades podem incluir o número de elementos, requisitos escritos para cada elemento ou para uma sequência de elementos como um todo, e valores de marcadores em índices específicos. Por exemplo, uma estrutura pode exigir exatamente dois elementos com "Name" no índice 0, ou pode exigir um primeiro marcador, um último marcador e uma sequência não vazia entre eles.

Um padrão de lista descreve uma forma combinando um requisito de contagem de elementos com padrões aninhados em posições ordenadas. Testa apenas os requisitos escritos no padrão: Um subpadrão de elemento testa o seu elemento correspondente, enquanto um padrão de corte pode permitir ou testar uma sequência de elementos que de outra forma não seriam emparelhados. Pode usar estas partes para fazer corresponder a uma contagem exata e a valores do marcador, capturar valores em posições fixas, permitir uma parte intermédia sem correspondência ou aplicar a essa parte intermédia um padrão aninhado.

Escolha um padrão de lista quando o tipo em tempo de compilação da entrada fornecer uma propriedade Length ou Count e acesso indexado aos elementos, que permite obter um elemento pela respetiva posição, como em input[index]. Arrays, List<T>, strings e spans são exemplos comuns. O compilador determina a elegibilidade a partir do tipo declarado em tempo de compilação da variável porque deve resolver esses membros necessários antes de o programa ser executado. A IEnumerable<T> interface por si só fornece enumeração em vez desses membros, mesmo quando o objeto de execução é uma coleção indexável.

Os padrões de lista usam um comprimento ou contagem e acesso indexado a elementos em vez de enumeração. Para tipos integrados comuns, a correspondência de padrões pode verificar apenas as posições nomeadas pelo padrão, em vez de iterar sobre todos os elementos. O custo dessas operações depende do tipo de entrada. Iterar uma coleção longa pode demorar tempo, por isso use um loop ou LINQ quando a decisão exigir examinar um número arbitrário de elementos em vez de posições específicas.

Corresponder a uma forma exata

O método seguinte reconhece um cabeçalho de duas colunas:

static bool IsHeader(string[] columns) =>
    columns is ["Name", "Score"];

A columns expressão é a entrada do padrão. ["Name", "Score"] contém dois padrões constantes. Um padrão de lista exato omite um padrão de fatia, requer exatamente dois elementos e aplica cada padrão aninhado ao elemento no mesmo índice. Este padrão descreve uma forma com uma contagem exata e dois valores marcadores: "Name" no índice 0 e "Score" no índice 1. Os padrões de elementos aninhados são opcionais: o padrão [] de lista vazia descreve e corresponde a uma sequência sem elementos.

Escolha um padrão de lista quando a forma combina a contagem de elementos com requisitos em posições ordenadas. Se apenas o número de elementos importar, um LengthCount ou padrão de propriedades, como items is { Count: 0 }, afirma essa intenção de forma mais direta.

Use um descarte para corresponder ao valor de qualquer elemento

O método seguinte lê o vencedor e o terceiro classificado a partir de uma ordem de chegada de três nomes:

static string GetAnnouncements(List<string> finishingOrder) =>
    finishingOrder switch
    {
        [var winner, _, var thirdPlace] =>
            $"Winner: {winner}; third place: {thirdPlace}",
        _ => "A complete three-runner result isn't available"
    };

Os var winner padrões e var thirdPlace declaram cada um uma variável. Quando o padrão de lista corresponde, o C# atribui o valor do elemento correspondente nessa posição à variável correspondente, para que o resultado possa usar winner e thirdPlace. O padrão _ de descarte aceita o segundo elemento e descarta o seu valor. Esta forma requer exatamente três elementos e dá significado específico às posições primeira e terceira, mas não requer valores específicos em nenhuma posição.

Escolha esta forma quando as posições fixas têm significado estável. Use um loop ou LINQ quando precisar de inspecionar um número arbitrário de elementos, transformar uma sequência, pesquisar ao longo dela ou realizar agregação.

Permitir elementos restantes num padrão de slice

Neste exemplo simplificado, uma linha de comandos pode começar com --verbose e conter outros argumentos, e assume-se que termina com o nome do ficheiro de entrada. O método seguinte reconhece formas com um nome de ficheiro na última posição e captura esse valor:

static string GetInputFile(string[] arguments) =>
    arguments switch
    {
        ["--verbose", .., var fileName] => $"Verbose processing: {fileName}",
        [.., var fileName] => $"Processing: {fileName}",
        [] => "No input file was provided"
    };

O .. permite que existam zero ou mais elementos restantes entre os padrões do primeiro e do último elemento. Um padrão de lista pode conter, no máximo, um padrão de fatia. O primeiro braço de troca descreve uma forma com pelo menos dois elementos: o marcador "--verbose" no índice 0, um nome de ficheiro na última posição e qualquer número de argumentos não correspondidos entre eles. O segmento independente não testa esses argumentos intermédios. O segundo braço aceita qualquer estrutura não vazia e captura o último elemento, enquanto o padrão vazio trata uma sequência sem elementos.

Uma fatia pode aparecer no início, meio ou fim de um padrão de lista. Use-o quando uma sequência de comprimento variável faz parte da forma, mas apenas as posições circundantes necessitam de testes de elementos. Use a iteração comum quando cada elemento precisa de processamento.

Aplicar um padrão a uma secção

Pode aplicar outro padrão à parte correspondente a ... O método seguinte testa se um array começa com "BEGIN", termina em "END", e tem pelo menos um elemento entre eles:

static bool HasContent(string[] entries) =>
    entries is ["BEGIN", .. { Length: > 0 }, "END"];

O padrão exterior requer primeiro o marcador "BEGIN" no índice 0 e "END" no último índice. O padrão { Length: > 0 } de propriedades adiciona então um requisito para a sequência correspondida pela fatia: deve conter pelo menos um elemento. Em conjunto, estes requisitos descrevem a forma completa. O padrão não testa os valores dos elementos dentro da fatia.

Utilize um subpadrão de divisão apenas quando a parte intermédia necessitar de um teste ou de uma captura. Se apenas os elementos de fronteira importam, o simples .. é mais simples.

Consulte também