Condividi tramite


Esercitazione: Usare il pattern matching per sviluppare algoritmi basati sui tipi e sui dati.

È possibile scrivere funzionalità che si comportano come se si estendessero tipi che potrebbero essere in altre librerie. Anche i pattern possono essere usati per creare funzionalità necessarie per l'applicazione che non sono caratteristiche fondamentali del tipo da estendere.

Questa esercitazione illustra come:

  • Riconoscere le situazioni in cui utilizzare la corrispondenza dei modelli.
  • Usare le espressioni di pattern matching per implementare la funzionalità in base ai tipi e ai valori delle proprietà.
  • Combinare il matching dei pattern con altre tecniche per creare algoritmi completi.

Prerequisiti

  • La versione più recente .NET SDK
  • editor di Visual Studio Code
  • Il DevKit C#

Istruzioni per l'installazione

Su Windows, usa questo file di configurazione WinGet per installare tutti i prerequisiti. Se è già installato un elemento, WinGet ignorerà questo passaggio.

  1. Scaricare il file e fare doppio clic per eseguirlo.
  2. Leggere il contratto di licenza, digitare ye selezionare Immettere quando viene richiesto di accettare.
  3. Se viene visualizzato un prompt di controllo dell'account utente lampeggiante nella barra delle applicazioni, consentire all'installazione di continuare.

In altre piattaforme è necessario installare ognuno di questi componenti separatamente.

  1. Scaricare il programma di installazione consigliato dalla pagina di download di .NET SDK e fare doppio clic per eseguirlo. La pagina di download rileva la piattaforma e consiglia il programma di installazione più recente per la piattaforma.
  2. Scarica il programma di installazione più recente dalla home page Visual Studio Code e fai doppio clic per eseguirlo. Questa pagina rileva anche la tua piattaforma e il collegamento dovrebbe essere corretto per il tuo sistema.
  3. Fare clic sul pulsante "Installa" nella pagina dell'estensione C# DevKit. Verrà aperto Visual Studio Code e viene chiesto se si vuole installare o abilitare l'estensione. Seleziona "install".

Per questa esercitazione si presuppone che l'utente abbia familiarità con C# e .NET, inclusa l'interfaccia della riga di comando di Visual Studio o di .NET.

Scenari per la corrispondenza di modelli

Lo sviluppo moderno spesso include l'integrazione dei dati da più origini e la presentazione di informazioni e approfondimenti da tali dati in una singola applicazione coerente. L'utente e il team non avranno il controllo o l'accesso su tutti i tipi che rappresentano i dati in ingresso.

La classica progettazione orientata agli oggetti richiederebbe la creazione di tipi nella tua applicazione che rappresentano ogni tipo di dati proveniente dalle molteplici origini dati. L'applicazione userebbe quindi i nuovi tipi, compilerebbe gerarchie di ereditarietà, creerebbe metodi virtuali e implementerebbe astrazioni. Queste tecniche funzionano e in alcuni casi sono i migliori strumenti. In altri casi è possibile scrivere meno codice. È possibile scrivere codice più chiaro usando tecniche che separano i dati dalle operazioni che modificano i dati.

In questa esercitazione si creerà e si esplorerà un'applicazione che accetta i dati in ingresso da più origini esterne per un singolo scenario. Verrà spiegato come i criteri di ricerca offrano un modo efficiente per utilizzare ed elaborare tali dati in modi non contemplati nel sistema originale.

Si prenda come esempio un'importante area metropolitana che gestisce il traffico applicando pedaggi e tariffe per le ore di punta. Si scrive un'applicazione che calcola i pedaggi in base al tipo di veicolo. I miglioramenti successivi incorporano i prezzi in base al numero di passeggeri del veicolo. Ulteriori miglioramenti aggiungono i prezzi in base all'ora e al giorno della settimana.

In base a questa breve descrizione, potrebbe essere stata rapidamente delineata una gerarchia di oggetti per modellare questo sistema. I dati provengono tuttavia da più origini, ad esempio altri sistemi di gestione di registrazione dei veicoli. Questi sistemi forniscono classi differenti per modellare i dati e non esiste un unico modello a oggetti che è possibile usare. Nell'esercitazione si useranno queste classi semplificate per la modellazione dei dati dei veicoli dai sistemi esterni, come illustrato nel codice seguente:

namespace ConsumerVehicleRegistration
{
    public class Car
    {
        public int Passengers { get; set; }
    }
}

namespace CommercialRegistration
{
    public class DeliveryTruck
    {
        public int GrossWeightClass { get; set; }
    }
}

namespace LiveryRegistration
{
    public class Taxi
    {
        public int Fares { get; set; }
    }

    public class Bus
    {
        public int Capacity { get; set; }
        public int Riders { get; set; }
    }
}

È possibile scaricare il codice iniziale dal repository GitHub dotnet/samples. È possibile osservare che le classi dei veicoli provengono da sistemi diversi e sono in spazi dei nomi diversi. Non è possibile utilizzare classi di base comuni, tranne System.Object.

Progetti di corrispondenza di modelli

Nell'esercitazione, lo scenario usato evidenzia i tipi di problemi che il pattern matching è particolarmente adatto a risolvere.

  • Gli oggetti da usare non sono in una gerarchia di oggetti che corrisponde ai propri obiettivi. È possibile che si stiano usando classi che fanno parte di sistemi non correlati.
  • Le funzionalità che si stanno aggiungendo non fanno parte dell'astrazione fondamentale per queste classi. Il pedaggio pagato da un veicolo cambia per i diversi tipi di veicoli, ma il pedaggio non è una funzione fondamentale del veicolo.

Quando la forma dei dati e le operazioni su tali dati non sono descritte insieme, le funzionalità dei criteri di ricerca in C# ne semplificano l'uso.

Implementare i calcoli di base per i pedaggi

Il calcolo dei pedaggi più semplice si basa solo sul tipo di veicolo:

  • Un Car costa $2,00.
  • Un Taxi costa $ 3,50.
  • Un Bus costa $ 5,00.
  • Un DeliveryTruck costa $10,00

Creare una nuova classe TollCalculator e implementare il pattern matching sul tipo di veicolo per ottenere l'importo del pedaggio. Nel codice seguente viene illustrata l'implementazione di TollCalculator.

using System;
using CommercialRegistration;
using ConsumerVehicleRegistration;
using LiveryRegistration;

namespace Calculators;

public class TollCalculator
{
    public decimal CalculateToll(object vehicle) =>
        vehicle switch
    {
        Car c           => 2.00m,
        Taxi t          => 3.50m,
        Bus b           => 5.00m,
        DeliveryTruck t => 10.00m,
        { }             => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
        null            => throw new ArgumentNullException(nameof(vehicle))
    };
}

Il codice precedente usa un'switchespressione (diversa da un'switchistruzione) che testa il criterio della dichiarazione. Un'espressione switch inizia con la variabile, vehicle nel codice precedente, seguita dalla parola chiave switch. Seguono quindi tutti gli elementi switch tra parentesi graffe. L'espressione switch perfeziona ulteriormente la sintassi che racchiude l'istruzione switch. La parola chiave case viene omessa e il risultato di ogni elemento è un'espressione. Gli ultimi due rami mostrano una nuova funzionalità del linguaggio. Nella dichiarazione { }, corrisponde a qualsiasi oggetto non nullo che non corrisponda a un ramo precedente. Questo elemento rileva eventuali tipi non corretti passati a questo metodo. Il caso { } deve seguire i casi per ogni tipo di veicolo. Se l'ordine fosse invertito, il caso { } prenderebbe la precedenza. Infine, il nullcriterio costante rileva quando null viene passato a questo metodo. Il criterio null può essere l'ultimo perché gli altri criteri corrispondono solo a un oggetto non Null del tipo corretto.

Per testare questo codice, usare il codice seguente in Program.cs:

using System;
using CommercialRegistration;
using ConsumerVehicleRegistration;
using LiveryRegistration;

using toll_calculator;

var tollCalc = new TollCalculator();

var car = new Car();
var taxi = new Taxi();
var bus = new Bus();
var truck = new DeliveryTruck();

Console.WriteLine($"The toll for a car is {tollCalc.CalculateToll(car)}");
Console.WriteLine($"The toll for a taxi is {tollCalc.CalculateToll(taxi)}");
Console.WriteLine($"The toll for a bus is {tollCalc.CalculateToll(bus)}");
Console.WriteLine($"The toll for a truck is {tollCalc.CalculateToll(truck)}");

try
{
    tollCalc.CalculateToll("this will fail");
}
catch (ArgumentException e)
{
    Console.WriteLine("Caught an argument exception when using the wrong type");
}
try
{
    tollCalc.CalculateToll(null!);
}
catch (ArgumentNullException e)
{
    Console.WriteLine("Caught an argument exception when using null");
}

Quel codice è incluso nel progetto iniziale, ma è commentato. Rimuovi i commenti e puoi testare quello che hai scritto.

Si può già osservare come i criteri consentano di creare algoritmi in cui il codice e i dati sono separati. L'espressione switch testa il tipo e genera valori diversi in base ai risultati. Si tratta solo dell'inizio.

Aggiungere i prezzi in base al numero degli occupanti

L'autorità di regolazione dei pedaggi vuole incoraggiare i conducenti a viaggiare al massimo della capacità. Si è deciso di far pagare di più i veicoli con un minor numero di passeggeri e di agevolare i veicoli che viaggiano al completo, offrendo prezzi più bassi:

  • Automobili e taxi senza passeggeri pagano un extra di $ 0,50.
  • Automobili e taxi con due passeggeri usufruiscono di uno sconto di $ 0,50.
  • Automobili e taxi con tre o più passeggeri usufruiscono di uno sconto di $ 1,00.
  • Gli autobus con meno del 50% dei posti occupati pagano un extra di $ 2,00.
  • Gli autobus con più del 90% dei posti occupati usufruiscono di uno sconto di $ 1,00.

Queste regole possono essere implementate usando un criterio di proprietà nella stessa espressione switch. Un modello di proprietà confronta un valore della proprietà con un valore costante. Dopo aver determinato il tipo, il criterio di proprietà esamina le proprietà dell'oggetto. Il caso singolo di Car si espande a quattro casi diversi.

vehicle switch
{
    Car {Passengers: 0} => 2.00m + 0.50m,
    Car {Passengers: 1} => 2.0m,
    Car {Passengers: 2} => 2.0m - 0.50m,
    Car                 => 2.00m - 1.0m,

    // ...
};

I primi tre case testano il tipo come Car, quindi controllano il valore della proprietà Passengers. Se entrambi corrispondono, l'espressione viene valutata e restituita.

Anche i casi dei taxi si espanderanno in modo analogo.

vehicle switch
{
    // ...

    Taxi {Fares: 0}  => 3.50m + 1.00m,
    Taxi {Fares: 1}  => 3.50m,
    Taxi {Fares: 2}  => 3.50m - 0.50m,
    Taxi             => 3.50m - 1.00m,

    // ...
};

Successivamente, implementa le regole di occupazione espandendo i casi per gli autobus, come illustrato nell'esempio seguente.

vehicle switch
{
    // ...

    Bus b when ((double)b.Riders / (double)b.Capacity) < 0.50 => 5.00m + 2.00m,
    Bus b when ((double)b.Riders / (double)b.Capacity) > 0.90 => 5.00m - 1.00m,
    Bus => 5.00m,

    // ...
};

L'autorità di regolazione dei pedaggi non considera il numero di passeggeri dei furgoni, L'ammontare dei pedaggi viene invece calcolato sulla base della classe di peso dei furgoni, come indicato di seguito:

  • I furgoni oltre le 5000 libbre (2268 kg) pagano un extra di $ 5,00.
  • I furgoni leggeri, sotto le 3000 libbre (1360 kg), usufruiscono di uno sconto di $ 2,00.

Tale regola viene implementata con il codice seguente:

vehicle switch
{
    // ...

    DeliveryTruck t when (t.GrossWeightClass > 5000) => 10.00m + 5.00m,
    DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
    DeliveryTruck => 10.00m,
};

Il codice precedente illustra la clausola when di un braccio di switch. La clausola when viene usata per testare condizioni diverse dall'uguaglianza per una proprietà. Al termine, si avrà un metodo molto simile al seguente codice:

vehicle switch
{
    Car {Passengers: 0}        => 2.00m + 0.50m,
    Car {Passengers: 1}        => 2.0m,
    Car {Passengers: 2}        => 2.0m - 0.50m,
    Car                        => 2.00m - 1.0m,

    Taxi {Fares: 0}  => 3.50m + 1.00m,
    Taxi {Fares: 1}  => 3.50m,
    Taxi {Fares: 2}  => 3.50m - 0.50m,
    Taxi             => 3.50m - 1.00m,

    Bus b when ((double)b.Riders / (double)b.Capacity) < 0.50 => 5.00m + 2.00m,
    Bus b when ((double)b.Riders / (double)b.Capacity) > 0.90 => 5.00m - 1.00m,
    Bus => 5.00m,

    DeliveryTruck t when (t.GrossWeightClass > 5000) => 10.00m + 5.00m,
    DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
    DeliveryTruck => 10.00m,

    { }     => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
    null    => throw new ArgumentNullException(nameof(vehicle))
};

Molti di questi bracci interruttori sono esempi di pattern ricorsivi. Ad esempio, Car { Passengers: 1} mostra un modello costante in un pattern di proprietà.

È possibile rendere meno ripetitivo questo codice usando switch annidate. Negli esempi precedenti, sia Car che Taxi hanno quattro braccia diverse. In entrambi i casi, è possibile creare un modello di dichiarazione che si integra in un modello costante. Questa tecnica è illustrata nel codice seguente:

public decimal CalculateToll(object vehicle) =>
    vehicle switch
    {
        Car c => c.Passengers switch
        {
            0 => 2.00m + 0.5m,
            1 => 2.0m,
            2 => 2.0m - 0.5m,
            _ => 2.00m - 1.0m
        },

        Taxi t => t.Fares switch
        {
            0 => 3.50m + 1.00m,
            1 => 3.50m,
            2 => 3.50m - 0.50m,
            _ => 3.50m - 1.00m
        },

        Bus b when ((double)b.Riders / (double)b.Capacity) < 0.50 => 5.00m + 2.00m,
        Bus b when ((double)b.Riders / (double)b.Capacity) > 0.90 => 5.00m - 1.00m,
        Bus b => 5.00m,

        DeliveryTruck t when (t.GrossWeightClass > 5000) => 10.00m + 5.00m,
        DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
        DeliveryTruck t => 10.00m,

        { }  => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
        null => throw new ArgumentNullException(nameof(vehicle))
    };

Nell'esempio precedente l'uso di un'espressione ricorsiva indica che non si ripetono gli elementi Car e Taxi che contengono elementi figlio che testano il valore della proprietà. Questa tecnica non viene usata per gli elementi Bus e DeliveryTruck perché tali elementi testano gli intervalli della proprietà, non i valori discreti.

Aggiungi i prezzi per le ore di punta

Come funzionalità finale, l'autorità di regolazione dei pedaggi vuole aggiungere i prezzi per le ore di punta. Durante le ore di punta del mattino e della sera, i pedaggi sono raddoppiati. Tale regola viene applicata al traffico in una sola direzione: in entrata in città durante le ore di punta del mattino e in uscita durante quelle serali. Negli altri orari della giornata lavorativa, i pedaggi aumentano del 50%. La sera tardi e la mattina presto, i pedaggi sono ridotti del 25%. Durante il fine settimana, si paga la normale tariffa, a qualsiasi ora. È possibile usare una serie di istruzioni if e else per esprimere questa operazione usando il codice seguente:

public decimal PeakTimePremiumIfElse(DateTime timeOfToll, bool inbound)
{
    if ((timeOfToll.DayOfWeek == DayOfWeek.Saturday) ||
        (timeOfToll.DayOfWeek == DayOfWeek.Sunday))
    {
        return 1.0m;
    }
    else
    {
        int hour = timeOfToll.Hour;
        if (hour < 6)
        {
            return 0.75m;
        }
        else if (hour < 10)
        {
            if (inbound)
            {
                return 2.0m;
            }
            else
            {
                return 1.0m;
            }
        }
        else if (hour < 16)
        {
            return 1.5m;
        }
        else if (hour < 20)
        {
            if (inbound)
            {
                return 1.0m;
            }
            else
            {
                return 2.0m;
            }
        }
        else // Overnight
        {
            return 0.75m;
        }
    }
}

Il codice precedente funziona correttamente, ma non è leggibile. È necessario collegare in sequenza tutti i casi di input e le istruzioni annidate if per ragionare sul codice. Invece, userai la corrispondenza di modelli per questa funzionalità, integrandola però con altre tecniche. È possibile creare una singola espressione con corrispondenza dei criteri che tenga in considerazione tutte le combinazioni di direzione, giorno della settimana e ora. Il risultato sarà un'espressione complessa, difficile da leggere e da comprendere, Risulta difficile garantire la correttezza. In alternativa, combinare questi metodi per compilare una tupla di valori che descrive in modo conciso tutti gli stati. Usare quindi la corrispondenza di modelli per calcolare un moltiplicatore per il pedaggio. La tupla contiene tre condizioni distinte:

  • Il giorno è un giorno feriale o un giorno del fine settimana.
  • La fascia oraria in cui il pedaggio viene riscosso.
  • La direzione è in città o fuori città

La tabella seguente mostra le combinazioni dei valori di input e il moltiplicatore dei prezzi per le ore di punta:

Giorno Tempo Direzione Premium
Giorno feriale ore di punta del mattino in entrata x 2,00
Giorno feriale traffico mattutino in uscita x 1,00
Giorno feriale ore diurne in entrata x 1,50
Giorno feriale ore diurne in uscita x 1,50
Giorno feriale ore di punta serali in entrata x 1,00
Giorno feriale traffico serale in uscita x 2,00
Giorno feriale durante la notte in entrata x 0,75
Giorno feriale durante la notte in uscita x 0,75
fine settimana ore di punta del mattino arrivo x 1,00
fine settimana ore di punta del mattino in uscita x 1,00
fine settimana periodo diurno in arrivo x 1,00
fine settimana ore diurne in uscita x 1,00
fine settimana ore di punta serali in entrata x 1,00
fine settimana ore di punta serali in uscita x 1,00
fine settimana durante la notte in arrivo x 1,00
fine settimana durante la notte in uscita x 1,00

Sono presenti 16 combinazioni diverse delle tre variabili. Combinando alcune delle condizioni, si semplificherà l'espressione switch finale.

Il sistema che raccoglie i pedaggi usa una struttura DateTime per l'ora in cui il pedaggio è stato riscosso. Costruire metodi membri che creano le variabili dalla tabella precedente. La funzione seguente utilizza un'espressione switch con pattern matching per esprimere se DateTime rappresenta il fine settimana o un giorno feriale.

private static bool IsWeekDay(DateTime timeOfToll) =>
    timeOfToll.DayOfWeek switch
    {
        DayOfWeek.Monday    => true,
        DayOfWeek.Tuesday   => true,
        DayOfWeek.Wednesday => true,
        DayOfWeek.Thursday  => true,
        DayOfWeek.Friday    => true,
        DayOfWeek.Saturday  => false,
        DayOfWeek.Sunday    => false
    };

Questo metodo è corretto, ma è ripetitivo. È possibile semplificarlo, come illustrato nel codice seguente:

private static bool IsWeekDay(DateTime timeOfToll) =>
    timeOfToll.DayOfWeek switch
    {
        DayOfWeek.Saturday => false,
        DayOfWeek.Sunday => false,
        _ => true
    };

Aggiungere quindi una funzione simile per classificare l'ora in blocchi di:

private enum TimeBand
{
    MorningRush,
    Daytime,
    EveningRush,
    Overnight
}

private static TimeBand GetTimeBand(DateTime timeOfToll) =>
    timeOfToll.Hour switch
    {
        < 6 or > 19 => TimeBand.Overnight,
        < 10 => TimeBand.MorningRush,
        < 16 => TimeBand.Daytime,
        _ => TimeBand.EveningRush,
    };

Si aggiunge un elemento enum privato per convertire ogni intervallo di tempo in un valore discreto. Il metodo GetTimeBand usa quindi criteri relazionali e criteri congiuntivior. Un criterio relazionale consente di testare un valore numerico usando <, >, <= o >=. Il criterio or verifica se un'espressione corrisponde a uno o più criteri. Inoltre, è possibile usare un criterio and per assicurarsi che un'espressione corrisponda a due criteri distinti e un criterio not per verificare che un'espressione non corrisponda a un criterio.

Dopo aver creato questi metodi, è possibile usare un'altra espressione switch con il pattern di tupla per calcolare il sovrapprezzo. È possibile creare un'espressione switch con tutti i 16 elementi:

public decimal PeakTimePremiumFull(DateTime timeOfToll, bool inbound) =>
    (IsWeekDay(timeOfToll), GetTimeBand(timeOfToll), inbound) switch
    {
        (true, TimeBand.MorningRush, true) => 2.00m,
        (true, TimeBand.MorningRush, false) => 1.00m,
        (true, TimeBand.Daytime, true) => 1.50m,
        (true, TimeBand.Daytime, false) => 1.50m,
        (true, TimeBand.EveningRush, true) => 1.00m,
        (true, TimeBand.EveningRush, false) => 2.00m,
        (true, TimeBand.Overnight, true) => 0.75m,
        (true, TimeBand.Overnight, false) => 0.75m,
        (false, TimeBand.MorningRush, true) => 1.00m,
        (false, TimeBand.MorningRush, false) => 1.00m,
        (false, TimeBand.Daytime, true) => 1.00m,
        (false, TimeBand.Daytime, false) => 1.00m,
        (false, TimeBand.EveningRush, true) => 1.00m,
        (false, TimeBand.EveningRush, false) => 1.00m,
        (false, TimeBand.Overnight, true) => 1.00m,
        (false, TimeBand.Overnight, false) => 1.00m,
    };

Il codice precedente funziona, ma può essere semplificato. Tutte le otto combinazioni per il fine settimana hanno lo stesso pedaggio. È possibile sostituire tutte le otto combinazioni con la sola riga seguente:

(false, _, _) => 1.0m,

Sia traffico in entrata che quello in uscita hanno lo stesso moltiplicatore durante le ore diurne e notturne dei giorni feriali. Questi quattro bracci dell'interruttore possono essere sostituiti con le due righe seguenti.

(true, TimeBand.Overnight, _) => 0.75m,
(true, TimeBand.Daytime, _)   => 1.5m,

Dopo le due modifiche, il codice dovrebbe essere simile al seguente:

public decimal PeakTimePremium(DateTime timeOfToll, bool inbound) =>
    (IsWeekDay(timeOfToll), GetTimeBand(timeOfToll), inbound) switch
    {
        (true, TimeBand.MorningRush, true)  => 2.00m,
        (true, TimeBand.MorningRush, false) => 1.00m,
        (true, TimeBand.Daytime,     _)     => 1.50m,
        (true, TimeBand.EveningRush, true)  => 1.00m,
        (true, TimeBand.EveningRush, false) => 2.00m,
        (true, TimeBand.Overnight,   _)     => 0.75m,
        (false, _,                   _)     => 1.00m,
    };

È infine possibile rimuovere le due fasce orarie di punta che pagano il prezzo normale. Una volta rimosse quelle braccia, è possibile sostituire false con un discard (_) nel ramo finale dello switch. Il metodo finale sarà il seguente:

public decimal PeakTimePremium(DateTime timeOfToll, bool inbound) =>
    (IsWeekDay(timeOfToll), GetTimeBand(timeOfToll), inbound) switch
    {
        (true, TimeBand.Overnight, _) => 0.75m,
        (true, TimeBand.Daytime, _) => 1.5m,
        (true, TimeBand.MorningRush, true) => 2.0m,
        (true, TimeBand.EveningRush, false) => 2.0m,
        _ => 1.0m,
    };

Questo esempio illustra uno dei vantaggi della corrispondenza dei pattern: i rami dei pattern vengono valutati in ordine. Se si modifica l'ordine in modo che un ramo precedente gestisca uno dei case successivi, il compilatore avverte che il codice non è raggiungibile. Grazie alle regole del linguaggio, è stato più facile eseguire le semplificazioni precedenti con la certezza che il codice non fosse modificato.

Il pattern matching rende alcuni tipi di codice più leggibili e costituisce un'alternativa alle tecniche orientate agli oggetti quando non è possibile aggiungere codice alle classi. Nel cloud i dati e le funzionalità sono separati. La forma dei dati e le operazioni su di essi non sono necessariamente descritte insieme. In questa esercitazione i dati esistenti sono stati utilizzati in modi completamente diversi dalla funzione originale. Il pattern matching ha permesso di scrivere funzionalità che hanno eseguito l'override di tali tipi, anche se non era possibile estenderli.

Passaggi successivi

È possibile scaricare il codice completo dal repository GitHub dotnet/samples. Esplora gli schemi da solo e aggiungi questa tecnica alle attività di programmazione abituali. L'apprendimento di queste tecniche offre un altro modo per affrontare i problemi e creare nuove funzionalità.

Vedi anche