Padrões de lista e de slice

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 completas sobre tipos compatíveis e idiomas, consulte padrões de listas na referência da linguagem.

A forma de uma sequência é o conjunto de propriedades observáveis que um padrão requer. Essas propriedades podem incluir o número de elementos, requisitos gravados para cada elemento ou para uma sequência de elementos como um todo e valores de marcador em índices específicos. Por exemplo, uma estrutura pode exigir exatamente dois elementos com "Name" no índice 0, ou então pode exigir o primeiro marcador, o ú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. Ele testa apenas os requisitos descritos no padrão: um subpadrão de um elemento testa seu elemento correspondente, enquanto um padrão de fatia pode permitir ou testar uma sequência de elementos que, de outra forma, não teriam correspondência. Você pode usar essas partes para corresponder a uma quantidade exata e aos valores do marcador, capturar valores em posições fixas, permitir uma parte central sem correspondência ou aplicar um padrão aninhado a essa parte central.

Escolha um padrão de lista quando o tipo da entrada em tempo de compilação fornecer uma propriedade Length ou Count, além de acesso indexado a elementos, que recupera um elemento por sua posição, como em input[index]. Matrizes, List<T>cadeias de caracteres e intervalos são exemplos comuns. O compilador determina a elegibilidade com base no tipo da variável declarado em tempo de compilação, porque ele precisa resolver esses membros obrigatórios antes da execução do programa. A IEnumerable<T> interface por si só fornece enumeração em vez desses membros, mesmo quando o objeto runtime é uma coleção indexável.

Os padrões de lista usam um tamanho ou contagem e acesso indexado a elementos em vez de usar enumeração. Para tipos internos mais comuns, a correspondência de padrões pode verificar apenas as posições nomeadas pelo padrão, em vez de iterar por todos os elementos. O custo dessas operações depende do tipo de entrada. Iterar uma coleção longa pode levar tempo, portanto, 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 exatamente a uma forma

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

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

A columns expressão é a entrada padrão. ["Name", "Score"] contém dois padrões constantes. Um padrão exato de lista omite um padrão de fatiamento, requer exatamente dois elementos e aplica cada padrão aninhado ao elemento de mesmo índice. Esse padrão descreve uma forma com uma contagem exata e dois valores de marcador: "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 estrutura combinar uma contagem de elementos com requisitos em posições específicas e ordenadas. Se apenas o número de elementos for importante, um Length ou Count padrão de propriedade, como items is { Count: 0 }, declara essa intenção mais diretamente.

Usar um descarte para corresponder a qualquer valor de um elemento

O método a seguir obtém o vencedor e o terceiro colocado de uma ordem de chegada com 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 padrões var winner 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 ser usado winner e thirdPlace. O padrão _ de descarte aceita o segundo elemento e descarta seu valor. Essa forma requer exatamente três elementos e dá à primeira e à terceira posições um significado específico, mas não requer valores específicos em nenhuma posição.

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

Permitir elementos restantes com um padrão de segmentação

Neste exemplo simplificado, uma linha de comando pode começar com --verbose e conter outros argumentos, e presume-se que termine com o nome do arquivo de entrada. O método a seguir reconhece formas com um nome de arquivo 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 padrão de fatia.. permite que haja 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 ramo do switch descreve uma estrutura com pelo menos dois elementos: o marcador "--verbose" no índice 0, um nome de arquivo na última posição e qualquer número de argumentos não correspondidos entre eles. A fatia autônoma não testa esses argumentos intermediários. O segundo braço aceita qualquer forma não íntegra e captura seu último elemento, enquanto o padrão vazio manipula uma sequência sem elementos.

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

Aplicar um padrão a um segmento

Você pode aplicar outro padrão à parte correspondida por ... O método a seguir testa se uma matriz começa com "BEGIN", termina com "END", e tem pelo menos um elemento entre eles:

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

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

Use um subpadrão de segmento somente quando a parte central em si exigir um teste ou uma captura. Se apenas os elementos de borda forem importantes, o simples .. é suficiente.

Consulte também