Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo tutorial illustra come usare il match di pattern per esaminare i dati in C#. Si scrivono piccole quantità di codice, quindi si compila ed esegue tale codice. L'esercitazione contiene una serie di lezioni che esplorano diverse categorie di tipi in C#. Queste lezioni illustrano i concetti fondamentali del linguaggio C#.
Suggerimento
Quando un blocco di frammenti di codice include il pulsante "Esegui", il pulsante apre la finestra interattiva o sostituisce il codice esistente nella finestra interattiva. Quando il frammento di codice non include un pulsante "Esegui", è possibile copiare il codice e aggiungerlo alla finestra interattiva corrente.
Le esercitazioni precedenti hanno dimostrato i tipi predefiniti e i tipi che definisci tu stesso come tuple o record. Le istanze di questi tipi possono essere controllate in base a un modello. Se un'istanza corrisponde a un modello determina le azioni eseguite dal programma. Negli esempi seguenti si noterà ?
dopo i nomi dei tipi. Questo simbolo consente che il valore di questo tipo sia null (ad esempio, bool?
può essere true
o false
null
). Per altre informazioni, vedere Tipi di valore annullabile. Iniziamo a esplorare come usare i modelli.
Abbina un valore
Tutti gli esempi di questa esercitazione usano l'input di testo che rappresenta una serie di transazioni bancarie come input con valori delimitati da virgole (CSV). In ognuno degli esempi è possibile trovare una corrispondenza tra il record e un criterio usando un'espressione is
o switch
. Questo primo esempio divide ogni riga sul carattere ,
e quindi confronta il primo campo di stringa con il valore "DEPOSIT" o "WITHDRAWAL" utilizzando un'espressione . Quando corrisponde, l'importo della transazione viene aggiunto o dedotto dal saldo corrente del conto. Per visualizzare il funzionamento, premere il pulsante "Esegui":
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}");
}
}
Esaminare l'output. È possibile notare che ogni riga viene elaborata confrontando il valore del testo nel primo campo. L'esempio precedente potrebbe essere costruito in modo analogo usando l'operatore ==
per verificare che due string
valori siano uguali. Confrontare una variabile con una costante è un elemento fondamentale per la corrispondenza di modelli. Esploriamo insieme altri elementi fondamentali che fanno parte dell'abbinamento di modelli.
Corrispondenze delle enumerazioni
Un altro uso comune per la corrispondenza dei criteri è la corrispondenza con i valori di un enum
tipo. Questo esempio successivo elabora i record di input per creare una tupla in cui il primo valore è un enum
valore che annota un deposito o un prelievo. Il secondo valore è il valore della transazione. Per visualizzare il funzionamento, premere il pulsante "Esegui":
Avvertimento
Non copiare e incollare. Per eseguire gli esempi seguenti, è necessario reimpostare la finestra interattiva. Se si commette un errore, la finestra si blocca ed è necessario aggiornare la pagina per continuare.
public static class ExampleProgram
{
const 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
""";
public static void Main()
{
double 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}");
}
}
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);
}
}
}
}
public enum TransactionType
{
Deposit,
Withdrawal,
Invalid
}
Nell'esempio precedente viene usata anche un'istruzione if
per controllare il valore di un'espressione enum
. Un'altra forma di corrispondenza di schemi utilizza un'espressione switch
. Esploriamo la sintassi e vediamo come usarla.
Corrispondenze complete con switch
Una serie di if
espressioni può testare una serie di condizioni. Tuttavia, il compilatore non è in grado di stabilire se una serie di if
istruzioni è esaustiva o se le condizioni successive if
vengono sommate da condizioni precedenti. L'espressione switch
garantisce che entrambe le caratteristiche vengano soddisfatte, con un minor numero di bug nelle app. Proviamoci e sperimentiamo. Copiare il codice seguente. Sostituire le due if
istruzioni nella finestra interattiva con l'espressione switch
copiata. Dopo aver modificato il codice, premere il pulsante "Esegui" nella parte superiore della finestra interattiva per eseguire il nuovo esempio.
currentBalance += transaction switch
{
(TransactionType.Deposit, var amount) => amount,
(TransactionType.Withdrawal, var amount) => -amount,
_ => 0.0,
};
Quando si esegue il codice, si noterà che funziona allo stesso modo. Per dimostrare la sussunzione, riordinare i rami dello switch come mostrato nel frammento di codice seguente.
currentBalance += transaction switch
{
(TransactionType.Deposit, var amount) => amount,
_ => 0.0,
(TransactionType.Withdrawal, var amount) => -amount,
};
Dopo aver riordinato le leve del commutatore, premi il pulsante "Esegui". Il compilatore genera un errore perché il arm con _
corrisponde a ogni valore. Di conseguenza, quel braccio finale con TransactionType.Withdrawal
non viene mai eseguito. Il compilatore indica che nel codice si è verificato un errore.
Il compilatore genera un avviso se l'espressione testata in un'espressione switch
potrebbe contenere valori che non corrispondono ad alcun arm switch. Se alcuni valori potrebbero non corrispondere a qualsiasi condizione, l'espressione switch
non è esaustiva. Il compilatore genera anche un avviso se alcuni valori dell'input non corrispondono ad alcuna delle braccia del commutatore. Ad esempio, se si rimuove la riga con _ => 0.0,
, tutti i valori non validi non corrispondono. In fase di esecuzione, l'operazione avrà esito negativo. Dopo aver installato .NET SDK e aver compilato programmi nell'ambiente, è possibile testare questo comportamento. L'esperienza online non visualizza avvisi nella finestra di output.
Modelli di tipo
Per completare questa esercitazione, esaminiamo un'altra componente fondamentale per la corrispondenza delle strutture: il modello di tipo. Un criterio di tipo verifica un'espressione in fase di esecuzione per verificare se è il tipo specificato. È possibile usare un test di tipo con un'espressione is
o un'espressione switch
. Modifichiamo l'esempio corrente in due modi. Prima di tutto, invece di una tupla, creiamo i tipi di record Deposit
e Withdrawal
che rappresentano le transazioni. Aggiungere le dichiarazioni seguenti nella parte inferiore della finestra interattiva:
public record Deposit(double Amount, string description);
public record Withdrawal(double Amount, string description);
Aggiungere quindi questo metodo dopo il Main
metodo per analizzare il testo e restituire una serie di record:
public 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;
}
}
Sostituire infine il foreach
ciclo nel Main
metodo con il codice seguente:
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}");
}
Premere quindi il pulsante "Esegui" per visualizzare i risultati. Questa versione finale testa l'input rispetto a un tipo.
Il pattern matching fornisce un vocabolario per confrontare un'espressione con delle proprietà. I modelli possono includere il tipo dell'espressione, i valori di tipi, i valori delle proprietà e le combinazioni di tali tipi. Il confronto delle espressioni con un modello può essere più chiaro di molti if
confronti. Sono stati esaminati alcuni dei modelli che è possibile usare per trovare le corrispondenze con le espressioni. Esistono molti altri modi per utilizzare il matching dei pattern nelle vostre applicazioni. Per prima cosa, visitare il sito .NET per scaricare .NET SDK, creare un progetto nel computer e continuare a scrivere codice. Durante l'esplorazione, è possibile ottenere altre informazioni sui criteri di ricerca in C# negli articoli seguenti: