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.
Este tutorial ensina como usar a correspondência de padrões para inspecionar dados em C#. Você escreve pequenas quantidades de código e, em seguida, compila e executa esse código. O tutorial contém uma série de lições que exploram diferentes tipos de padrões compatíveis com o C#. Essas lições ensinam os conceitos básicos da linguagem C#.
Neste tutorial, você:
- Inicie um Codespace do GitHub com um ambiente de desenvolvimento em C#.
- Teste dados para valores discretos.
- Corresponder dados de enumeração com o valor.
- Crie correspondências exaustivas usando expressões
switch. - Corresponda tipos utilizando padrões de tipo.
Pré-requisitos
Você deve ter um dos seguintes:
- Uma conta do GitHub para usar os Codespaces do GitHub. Se você ainda não tiver uma, poderá criar uma conta gratuita em GitHub.com.
- Um computador com as seguintes ferramentas instaladas:
Igualar a um valor
Os tutoriais anteriores demonstraram tipos embutidos e tipos que você define como tuplas ou tipos de registros. Você pode verificar instâncias desses tipos em relação a um padrão. Se uma instância corresponde a um padrão determina as ações que seu programa executa. Nos exemplos abaixo, você verá os nomes de tipo seguidos por ?. Esse símbolo permite que o valor desse tipo seja nulo (por exemplo, bool? pode ser true, falseou null). Para obter mais informações, consulte tipos de valor anuláveis. Vamos começar a explorar como você pode usar padrões.
Abra uma janela do navegador e acesse os codespaces do GitHub. Crie um novo codespace com base no Modelo do .NET. Se você concluiu outros tutoriais nesta série, poderá abrir esse codespace.
Quando o codespace for carregado, crie um novo arquivo na pasta de tutoriais chamada patterns.cs.
Abra seu novo arquivo.
Todos os exemplos neste tutorial usam a entrada de texto que representa uma série de transações bancárias como entrada de CSV (valores separados por vírgulas). Em cada uma das amostras, você pode corresponder o registro a um padrão usando uma expressão
isouswitch. Este primeiro exemplo divide cada linha no caractere,e, em seguida, verifica se o primeiro campo de cadeia de caracteres é igual ao valor "DEPOSIT" ou "WITHDRAWAL" usando uma expressãois. Quando corresponde, o valor da transação é adicionado ou deduzido do saldo da conta atual. Para vê-lo funcionar, adicione o seguinte código ao patterns.cs:string bankRecords = """ DEPOSIT, 10000, Initial balance DEPOSIT, 500, regular deposit WITHDRAWAL, 1000, rent DEPOSIT, 2000, freelance payment WITHDRAWAL, 300, groceries DEPOSIT, 700, gift from friend WITHDRAWAL, 150, utility bill DEPOSIT, 1200, tax refund WITHDRAWAL, 500, car maintenance DEPOSIT, 400, cashback reward WITHDRAWAL, 250, dining out DEPOSIT, 3000, bonus payment WITHDRAWAL, 800, loan repayment DEPOSIT, 600, stock dividends WITHDRAWAL, 100, subscription fee DEPOSIT, 1500, side hustle income WITHDRAWAL, 200, fuel expenses DEPOSIT, 900, refund from store WITHDRAWAL, 350, shopping DEPOSIT, 2500, project milestone payment WITHDRAWAL, 400, entertainment """; double currentBalance = 0.0; var reader = new StringReader(bankRecords); string? line; while ((line = reader.ReadLine()) is not null) { if (string.IsNullOrWhiteSpace(line)) continue; // Split the line based on comma delimiter and trim each part string[] parts = line.Split(','); string? transactionType = parts[0]?.Trim(); if (double.TryParse(parts[1].Trim(), out double amount)) { // Update the balance based on transaction type if (transactionType?.ToUpper() is "DEPOSIT") currentBalance += amount; else if (transactionType?.ToUpper() is "WITHDRAWAL") currentBalance -= amount; Console.WriteLine($"{line.Trim()} => Parsed Amount: {amount}, New Balance: {currentBalance}"); } }Em seguida, digite o seguinte texto na janela do terminal:
cd tutorials dotnet patterns.csVerifique a saída. Você pode ver que cada linha é processada comparando o valor do texto no primeiro campo.
Da mesma forma, você pode construir o exemplo anterior usando o == operador para testar se dois string valores são iguais. Comparar uma variável com uma constante é um bloco de construção básico para correspondência de padrões. Vamos explorar mais dos blocos de construção que fazem parte da correspondência de padrões.
Correspondências de Enum
Outro uso comum para correspondência de padrões é a correspondência nos valores de um enum tipo. O exemplo a seguir processa os registros de entrada para criar uma tupla onde o primeiro valor é um enum valor que indica se é um depósito ou um saque. O segundo valor é o valor da transação.
Adicione o código a seguir ao final do arquivo de origem. Ela define a
TransactionTypeenumeração:public enum TransactionType { Deposit, Withdrawal, Invalid }Adicione uma função para analisar uma transação bancária em uma tupla que contém o tipo de transação e o valor da transação. Adicione o seguinte código antes da declaração da
TransactionTypeenumeração:static IEnumerable<(TransactionType type, double amount)> TransactionRecords(string inputText) { var reader = new StringReader(inputText); string? line; while ((line = reader.ReadLine()) is not null) { string[] parts = line.Split(','); string? transactionType = parts[0]?.Trim(); if (double.TryParse(parts[1].Trim(), out double amount)) { // Update the balance based on transaction type if (transactionType?.ToUpper() is "DEPOSIT") yield return (TransactionType.Deposit, amount); else if (transactionType?.ToUpper() is "WITHDRAWAL") yield return (TransactionType.Withdrawal, amount); } else { yield return (TransactionType.Invalid, 0.0); } } }Adicione um novo loop para processar os dados da transação usando a
TransactionTypeenumeração que você declarou:currentBalance = 0.0; foreach (var transaction in TransactionRecords(bankRecords)) { if (transaction.type == TransactionType.Deposit) currentBalance += transaction.amount; else if (transaction.type == TransactionType.Withdrawal) currentBalance -= transaction.amount; Console.WriteLine($"{transaction.type} => Parsed Amount: {transaction.amount}, New Balance: {currentBalance}"); }
O exemplo anterior também usa uma instrução if para verificar o valor de uma expressão enum . Outra forma de correspondência de padrões usa uma switch expressão. Vamos explorar essa sintaxe e como usá-la.
Resultados exaustivos com switch
Uma série de if declarações pode avaliar uma sequência de condições. No entanto, o compilador não pode dizer se uma série de if instruções são exaustivas ou se as condições posteriores if são subsumidas por condições anteriores.
Exaustivo significa que uma das cláusulas if ou else na série de testes lida com todas as entradas possíveis. Se uma série de if declarações é abrangente, toda entrada possível satisfaz pelo menos uma cláusula if ou else.
Subsunção significa que uma cláusula posterior if ou else não pode ser alcançada porque cláusulas anteriores if ou else correspondem a todas as entradas possíveis. Por exemplo, no código de exemplo a seguir, uma cláusula nunca corresponde:
int n = GetNumber();
if (n < 20)
Console.WriteLine("n is less than 20");
else if (n < 10)
Console.WriteLine("n is less than 10"); // unreachable
else
Console.WriteLine("n is greater than 20");
A else if cláusula nunca corresponde porque cada número menor que 10 também é menor que 20. A switch expressão garante que ambas as características sejam atendidas, o que resulta em menos bugs em seus aplicativos. Vamos tentar e experimentar.
Copie o código a seguir. Substitua as duas instruções
ifem seu loopforeachpela expressãoswitchque você copiou.currentBalance += transaction switch { (TransactionType.Deposit, var amount) => amount, (TransactionType.Withdrawal, var amount) => -amount, _ => 0.0, };Digite
dotnet patterns.csna janela do terminal para executar o novo exemplo.Ao executar o código, você verá que ele funciona da mesma forma.
Para demonstrar a subsumpição, reordene os braços do comutador, conforme mostrado no trecho de código a seguir.
currentBalance += transaction switch { (TransactionType.Deposit, var amount) => amount, _ => 0.0, (TransactionType.Withdrawal, var amount) => -amount, };Depois de reordenar os braços do switch, digite
dotnet patterns.csna janela do terminal. O compilador gera um erro porque o ramo com_corresponde a cada valor. Como resultado, aquele braço final comTransactionType.Withdrawalnunca é executado. O compilador informa que algo está errado em seu código.O compilador emitirá um aviso se a expressão testada em uma
switchexpressão puder conter valores que não correspondem a nenhum braço de comutador. Se alguns valores não corresponderem a qualquer condição, aswitchexpressão não será exaustiva. O compilador também emitirá um aviso se alguns valores da entrada não corresponderem a nenhum dos braços do comutador.Remova a linha com
_ => 0.0,, para que os valores inválidos não correspondam.Digite
dotnet patterns.cspara ver os resultados.O compilador emite um aviso. Os dados de teste são válidos, portanto, o programa funciona. No entanto, qualquer dado inválido causaria uma falha no runtime.
Padrões de tipo
Para concluir este tutorial, explore mais um bloco de construção para correspondência de padrões: o padrão de tipo. Um padrão de tipo testa uma expressão em tempo de execução para ver se é o tipo especificado. Você pode usar um teste de tipo com uma is expressão ou uma switch expressão. Modifique o exemplo atual de duas maneiras. Primeiro, em vez de uma tupla, construa tipos de registro Deposit e Withdrawal que representem as transações.
Adicione as seguintes declarações no final do arquivo de código:
public record Deposit(double Amount, string description); public record Withdrawal(double Amount, string description);Adicione esse método pouco antes da declaração da
TransactionTypeenumeração. Ele analisa o texto e retorna uma série de registros:static IEnumerable<object?> TransactionRecordType(string inputText) { var reader = new StringReader(inputText); string? line; while ((line = reader.ReadLine()) is not null) { string[] parts = line.Split(','); string? transactionType = parts[0]?.Trim(); if (double.TryParse(parts[1].Trim(), out double amount)) { // Update the balance based on transaction type if (transactionType?.ToUpper() is "DEPOSIT") yield return new Deposit(amount, parts[2]); else if (transactionType?.ToUpper() is "WITHDRAWAL") yield return new Withdrawal(amount, parts[2]); } yield return default; } }Adicione o seguinte código após o último
foreachloop:currentBalance = 0.0; foreach (var transaction in TransactionRecordType(bankRecords)) { currentBalance += transaction switch { Deposit d => d.Amount, Withdrawal w => -w.Amount, _ => 0.0, }; Console.WriteLine($" {transaction} => New Balance: {currentBalance}"); }Digite
dotnet patterns.csna janela do terminal para ver os resultados. Esta versão final testa a entrada em relação a um tipo.
A correspondência de padrões fornece um vocabulário para comparar uma expressão com características. Os padrões podem incluir o tipo da expressão, valores de tipos, valores de propriedade e combinações deles. Comparar expressões com um padrão pode ser mais claro do que várias if comparações. Você explorou alguns dos padrões que pode usar para corresponder a expressões. Há muitas outras maneiras de usar a correspondência de padrões em seus aplicativos. Ao explorar, você pode saber mais sobre a correspondência de padrões em C# nos seguintes artigos:
- Padrões correspondentes em C#
- Explorar o tutorial de correspondência de padrões
- Cenário de correspondência de padrões
Recursos de limpeza
O GitHub exclui automaticamente o Codespace após 30 dias de inatividade. Você concluiu todos os tutoriais desta série. Para excluir seu Codespace agora, abra uma janela do navegador e vá para seus Codespaces. Você deve ver uma lista de seus codespaces na janela. Selecione os três pontos (...) na entrada para o codespace do tutorial de aprendizado e selecione excluir.
Conteúdo relacionado
- Baixe e instale o SDK do .NET 10.
- Baixe e instale o Visual Studio Code.
- Baixe e instale o Kit de Desenvolvimento em C#.
- Explore a seção de conceitos básicos do C# para saber mais sobre C#.