Esercitazione: Utilizzo delle funzionalità di criteri di ricerca per estendere i tipi di datiTutorial: Using pattern matching features to extend data typesTutorial: Using pattern matching features to extend data types

In C# 7 sono state introdotte le funzionalità dei criteri di ricerca di base.C# 7 introduced basic pattern matching features. Tali funzionalità vengono estese in C# 8 con nuove espressioni e criteri.Those features are extended in C# 8 with new expressions and patterns. È possibile scrivere funzionalità che si comportano come se si estendessero tipi che potrebbero essere in altre librerie.You can write functionality that behaves as though you extended types that may be in other libraries. I criteri possono essere usati anche per creare funzionalità necessarie per l'applicazione che non sono funzioni fondamentali del tipo da estendere.Another use for patterns is to create functionality your application requires that isn't a fundamental feature of the type being extended.

In questa esercitazione si apprenderà come:In this tutorial, you'll learn how to:

  • Riconoscere le situazioni in cui usare i criteri di ricerca.Recognize situations where pattern matching should be used.
  • Usare le espressioni dei criteri di ricerca per implementare il comportamento in base ai tipi e ai valori delle proprietà.Use pattern matching expressions to implement behavior based on types and property values.
  • Combinare i criteri di ricerca con altre tecniche per creare algoritmi completi.Combine pattern matching with other techniques to create complete algorithms.

PrerequisitesPrerequisites

È necessario configurare il computer per l'esecuzione di .NET Core, incluso il compilatore c'è 8.0.You’ll need to set up your machine to run .NET Core, including the C# 8.0 compiler. Il compilatore di C'è 8 è disponibile a partire da Visual Studio 2019 versione 16.3 o .NET Core 3.0 SDK.The C# 8 compiler is available starting with Visual Studio 2019 version 16.3 or .NET Core 3.0 SDK.

Per questa esercitazione si presuppone che l'utente abbia familiarità con C# e .NET, inclusa l'interfaccia della riga di comando di .NET Core o Visual Studio.This tutorial assumes you're familiar with C# and .NET, including either Visual Studio or the .NET Core CLI.

Scenari per i criteri di ricercaScenarios for pattern matching

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.Modern development often includes integrating data from multiple sources and presenting information and insights from that data in a single cohesive application. L'utente e il team non avranno il controllo o l'accesso per tutti i tipi che rappresentano i dati in ingresso.You and your team won't have control or access for all the types that represent the incoming data.

La classica progettazione orientata agli oggetti eseguirebbe una chiamata per la creazione di tipi nell'applicazione che rappresentano ogni tipo di dati dalle diverse origini dati.The classic object-oriented design would call for creating types in your application that represent each data type from those multiple data sources. L'applicazione userebbe quindi i nuovi tipi, compilerebbe gerarchie di ereditarietà, creerebbe metodi virtuali e implementerebbe astrazioni.Then, your application would work with those new types, build inheritance hierarchies, create virtual methods, and implement abstractions. Queste tecniche funzionano e in alcuni casi sono i migliori strumenti.Those techniques work, and sometimes they are the best tools. In altri casi è possibile scrivere meno codice.Other times you can write less code. È possibile scrivere codice più chiaro usando tecniche che separano i dati dalle operazioni che modificano i dati.You can write more clear code using techniques that separate the data from the operations that manipulate that data.

In questa esercitazione si creerà e si esplorerà un'applicazione che accetta i dati in ingresso da più origini esterne per un singolo scenario.In this tutorial, you'll create and explore an application that takes incoming data from several external sources for a single 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.You'll see how pattern matching provides an efficient way to consume and process that data in ways that weren't part of the original system.

Si prenda come esempio un'importante area metropolitana che gestisce il traffico applicando pedaggi e tariffe per le ore di punta.Consider a major metropolitan area that is using tolls and peak time pricing to manage traffic. Si scrive un'applicazione che calcola i pedaggi in base al tipo di veicolo.You write an application that calculates tolls for a vehicle based on its type. I miglioramenti successivi incorporano i prezzi in base al numero di passeggeri del veicolo.Later enhancements incorporate pricing based on the number of occupants in the vehicle. Ulteriori miglioramenti aggiungono i prezzi in base all'ora e al giorno della settimana.Further enhancements add pricing based on the time and the day of the week.

In base a questa breve descrizione, potrebbe essere stata rapidamente delineata una gerarchia di oggetti per modellare questo sistema.From that brief description, you may have quickly sketched out an object hierarchy to model this system. I dati provengono tuttavia da più origini, ad esempio altri sistemi di gestione di registrazione dei veicoli.However, your data is coming from multiple sources like other vehicle registration management systems. Questi sistemi forniscono classi differenti per modellare i dati e non esiste un unico modello a oggetti che è possibile usare.These systems provide different classes to model that data and you don't have a single object model you can use. Nell'esercitazione si useranno queste classi semplificate per la modellazione dei dati dei veicoli dai sistemi esterni, come illustrato nel codice seguente:In this tutorial, you'll use these simplified classes to model for the vehicle data from these external systems, as shown in the following code:

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.You can download the starter code from the dotnet/samples GitHub repository. È possibile osservare che le classi dei veicoli provengono da sistemi diversi e sono in spazi dei nomi diversi.You can see that the vehicle classes are from different systems, and are in different namespaces. Non è possibile sfruttare classi di base comuni, tranne System.Object.No common base class, other than System.Object can be leveraged.

Progettazioni di criteri di ricercaPattern matching designs

Lo scenario usato in questa esercitazione evidenzia i tipi di problemi che è possibile risolvere usando i criteri di ricerca:The scenario used in this tutorial highlights the kinds of problems that pattern matching is well-suited to solve:

  • Gli oggetti da usare non sono in una gerarchia di oggetti che corrisponde ai propri obiettivi.The objects you need to work with aren't in an object hierarchy that matches your goals. È possibile che si stiano usando classi che fanno parte di sistemi non correlati.You may be working with classes that are part of unrelated systems.
  • Le funzionalità che si stanno aggiungendo non fanno parte dell'astrazione fondamentale per queste classi.The functionality you're adding isn't part of the core abstraction for these classes. Il pedaggio pagato da un veicolo cambia per i diversi tipi di veicoli, ma il pedaggio non è una funzione fondamentale del veicolo.The toll paid by a vehicle changes for different types of vehicles, but the toll isn't a core function of the vehicle.

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.When the shape of the data and the operations on that data are not described together, the pattern matching features in C# make it easier to work with.

Implementare i calcoli di base per i pedaggiImplement the basic toll calculations

Il calcolo dei pedaggi più semplice si basa solo sul tipo di veicolo:The most basic toll calculation relies only on the vehicle type:

  • Un veicolo Car paga $ 2,00.A Car is $2.00.
  • Un veicolo Taxi paga $ 3,50.A Taxi is $3.50.
  • Un veicolo Bus paga $ 5,00.A Bus is $5.00.
  • Un veicolo DeliveryTruck paga $ 10,00A DeliveryTruck is $10.00

Creare una nuova classe TollCalculator e implementare i criteri di ricerca per il tipo di veicolo per ottenere l'ammontare dei pedaggi.Create a new TollCalculator class, and implement pattern matching on the vehicle type to get the toll amount. Nel codice seguente viene illustrata l'implementazione di TollCalculator.The following code shows the initial implementation of the TollCalculator.

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

namespace toll_calculator
{
    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'espressione switch (diversa da un'istruzione switch) che testa il criterio del tipo.The preceding code uses a switch expression (not the same as a switch statement) that tests the type pattern. Un'espressione switch inizia con la variabile, vehicle nel codice precedente, seguita dalla parola chiave switch.A switch expression begins with the variable, vehicle in the preceding code, followed by the switch keyword. Seguono quindi tutti gli elementi switch tra parentesi graffe.Next comes all the switch arms inside curly braces. L'espressione switch perfeziona ulteriormente la sintassi che racchiude l'istruzione switch.The switch expression makes other refinements to the syntax that surrounds the switch statement. La parola chiave case viene omessa e il risultato di ogni elemento è un'espressione.The case keyword is omitted, and the result of each arm is an expression. Gli ultimi due elementi mostrano una nuova funzionalità del linguaggio.The last two arms show a new language feature. Il case { } corrisponde a eventuali oggetti non Null che non corrispondevano a un elemento precedente.The { } case matches any non-null object that didn't match an earlier arm. Questo elemento rileva eventuali tipi non corretti passati a questo metodo.This arm catches any incorrect types passed to this method. Il case { } deve seguire i case per ogni tipo di veicolo.The { } case must follow the cases for each vehicle type. Se l'ordine è stato invertito, il case { } deve avere la precedenza.If the order were reversed, the { } case would take precedence. Il criterio null infine rileva quando null viene passato a questo metodo.Finally, the null pattern detects when a null is passed to this method. Il criterio null può essere l'ultimo perché gli altri criteri dei tipi corrispondono solo a un oggetto non Null del tipo corretto.The null pattern can be last because the other type patterns match only a non-null object of the correct type.

Per testare questo codice, usare il codice seguente in Program.cs:You can test this code using the following code in Program.cs:

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

namespace toll_calculator
{
    class Program
    {
        static void Main(string[] args)
        {
            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");
            }
        }
    }
}

Tale codice è incluso nel progetto di avvio, ma è commentato. Rimuovere i commenti e testare ciò che hai scritto.That code is included in the starter project, but is commented out. Remove the comments, and you can test what you've written.

Si può già osservare come i criteri consentano di creare algoritmi in cui il codice e i dati sono separati.You're starting to see how patterns can help you create algorithms where the code and the data are separate. L'espressione switch testa il tipo e genera valori diversi in base ai risultati.The switch expression tests the type and produces different values based on the results. Si tratta solo dell'inizio.That's only the beginning.

Aggiungere i prezzi in base al numero degli occupantiAdd occupancy pricing

L'autorità di regolazione dei pedaggi vuole incoraggiare i conducenti a viaggiare al massimo della capacità.The toll authority wants to encourage vehicles to travel at maximum capacity. 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:They've decided to charge more when vehicles have fewer passengers, and encourage full vehicles by offering lower pricing:

  • Automobili e taxi senza passeggeri pagano un extra di $ 0,50.Cars and taxis with no passengers pay an extra $0.50.
  • Automobili e taxi con due passeggeri usufruiscono di uno sconto di $ 0,50.Cars and taxis with two passengers get a $0.50 discount.
  • Automobili e taxi con tre o più passeggeri usufruiscono di uno sconto di $ 1,00.Cars and taxis with three or more passengers get a $1.00 discount.
  • Gli autobus con meno del 50% dei posti occupati pagano un extra di $ 2,00.Buses that are less than 50% full pay an extra $2.00.
  • Gli autobus con più del 90% dei posti occupati usufruiscono di uno sconto di $ 1,00.Buses that are more than 90% full get a $1.00 discount.

Queste regole possono essere implementate usando il criterio di proprietà nella stessa espressione switch.These rules can be implemented using the property pattern in the same switch expression. Dopo aver determinato il tipo, il criterio di proprietà esamina le proprietà dell'oggetto.The property pattern examines properties of the object once the type has been determined. Il case singolo di Car si espande a quattro case diversi:The single case for a Car expands to four different cases:

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

    // ...
};

I primi tre case testano il tipo come Car, quindi controllano il valore della proprietà Passengers.The first three cases test the type as a Car, then check the value of the Passengers property. Se entrambi corrispondono, l'espressione viene valutata e restituita.If both match, that expression is evaluated and returned.

Si espanderanno in modo analogo anche i case dei taxi:You would also expand the cases for taxis in a similar manner:

vehicle switch
{
    // ...

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

    // ...
};

Nell'esempio precedente la clausola when è stata omessa nel case finale.In the preceding example, the when clause was omitted on the final case.

Successivamente, implementare le regole per il numero di occupanti espandendo i case per gli autobus, come illustrato nell'esempio seguente:Next, implement the occupancy rules by expanding the cases for buses, as shown in the following example:

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 b => 5.00m,

    // ...
};

L'autorità di regolazione dei pedaggi non considera il numero di passeggeri dei furgoni,The toll authority isn't concerned with the number of passengers in the delivery trucks. L'ammontare dei pedaggi viene invece calcolato sulla base della classe di peso dei furgoni, come indicato di seguito:Instead, they adjust the toll amount based on the weight class of the trucks as follows:

  • I furgoni oltre le 5000 libbre (2268 kg) pagano un extra di $ 5,00.Trucks over 5000 lbs are charged an extra $5.00.
  • I furgoni leggeri, sotto le 3000 libbre (1360 kg), usufruiscono di uno sconto di $ 2,00.Light trucks under 3000 lbs are given a $2.00 discount.

Tale regola viene implementata con il codice seguente:That rule is implemented with the following code:

vehicle switch
{
    // ...

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

Il codice precedente illustra la clausola when di un elemento switch.The preceding code shows the when clause of a switch arm. La clausola when viene usata per testare condizioni diverse dall'uguaglianza per una proprietà.You use the when clause to test conditions other than equality on a property. Al termine, si avrà un metodo molto simile al seguente:When you've finished, you'll have a method that looks much like the following:

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

    Taxi { Fares: 0}  => 3.50m + 1.00m,
    Taxi { Fares: 1 } => 3.50m,
    Taxi { Fares: 2}  => 3.50m - 0.50m,
    Taxi t            => 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))
};

Molti di questi elementi switch sono esempi di criteri ricorsivi.Many of these switch arms are examples of recursive patterns. Car { Passengers: 1}, ad esempio, mostra un criterio costante in un criterio di proprietà.For example, Car { Passengers: 1} shows a constant pattern inside a property pattern.

È possibile rendere meno ripetitivo questo codice usando switch annidate.You can make this code less repetitive by using nested switches. Negli esempi precedenti sia Car che Taxi hanno quattro diversi elementi.The Car and Taxi both have four different arms in the preceding examples. In entrambi i casi, è possibile creare un criterio di tipo che viene inserito in un criterio di proprietà.In both cases, you can create a type pattern that feeds into a property pattern. Questa tecnica è illustrata nel codice seguente:This technique is shown in the following code:

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à.In the preceding sample, using a recursive expression means you don't repeat the Car and Taxi arms containing child arms that test the property value. Questa tecnica non viene usata per gli elementi Bus e DeliveryTruck perché tali elementi testano gli intervalli della proprietà, non i valori discreti.This technique isn't used for the Bus and DeliveryTruck arms because those arms are testing ranges for the property, not discrete values.

Aggiungi i prezzi per le ore di puntaAdd peak pricing

Come funzionalità finale, l'autorità di regolazione dei pedaggi vuole aggiungere i prezzi per le ore di punta.For the final feature, the toll authority wants to add time sensitive peak pricing. Durante le ore di punta del mattino e della sera, i pedaggi sono raddoppiati.During the morning and evening rush hours, the tolls are doubled. 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.That rule only affects traffic in one direction: inbound to the city in the morning, and outbound in the evening rush hour. Negli altri orari della giornata lavorativa, i pedaggi aumentano del 50%.During other times during the workday, tolls increase by 50%. La sera tardi e la mattina presto, i pedaggi sono ridotti del 25%.Late night and early morning, tolls are reduced by 25%. Durante il fine settimana, si paga la normale tariffa, a qualsiasi ora.During the weekend, it's the normal rate, regardless of the time.

Per questa funzionalità si useranno i criteri di ricerca, che verranno però integrati con altre tecniche.You'll use pattern matching for this feature, but you'll integrate it with other techniques. È possibile creare una singola espressione con corrispondenza dei criteri che tenga in considerazione tutte le combinazioni di direzione, giorno della settimana e ora.You could build a single pattern match expression that would account for all the combinations of direction, day of the week, and time. Il risultato sarà un'espressione complessa,The result would be a complicated expression. difficile da leggere e da comprendere,It would be hard to read and difficult to understand. di cui sarebbe difficile garantire la correttezza.That makes it hard to ensure correctness. In alternativa, combinare questi metodi per compilare una tupla di valori che descrive in modo conciso tutti gli stati.Instead, combine those methods to build a tuple of values that concisely describes all those states. Usare quindi i criteri di ricerca per calcolare un moltiplicatore per il pedaggio.Then use pattern matching to calculate a multiplier for the toll. La tupla contiene tre condizioni distinte:The tuple contains three discrete conditions:

  • Il giorno, che è un giorno feriale o il fine settimana.The day is either a weekday or a weekend.
  • La fascia oraria in cui il pedaggio viene riscosso.The band of time when the toll is collected.
  • La direzione, in entrata in città o in uscita dalla cittàThe direction is into the city or out of the city

La tabella seguente mostra le combinazioni dei valori di input e il moltiplicatore dei prezzi per le ore di punta:The following table shows the combinations of input values and the peak pricing multiplier:

GiornoDay TempoTime DirectionDirection PremiumPremium
Giorno della settimanaWeekday ore di punta del mattinomorning rush in entratainbound x 2,00x 2.00
Giorno della settimanaWeekday ore di punta del mattinomorning rush in uscitaoutbound x 1,00x 1.00
Giorno della settimanaWeekday giornodaytime in entratainbound x 1,50x 1.50
Giorno della settimanaWeekday giornodaytime in uscitaoutbound x 1,50x 1.50
Giorno della settimanaWeekday ore di punta seralievening rush in entratainbound x 1,00x 1.00
Giorno della settimanaWeekday ore di punta seralievening rush in uscitaoutbound x 2,00x 2.00
Giorno della settimanaWeekday notteovernight in entratainbound x 0,75x 0.75
Giorno della settimanaWeekday notteovernight in uscitaoutbound x 0,75x 0.75
fine settimanaWeekend ore di punta del mattinomorning rush in entratainbound x 1,00x 1.00
fine settimanaWeekend ore di punta del mattinomorning rush in uscitaoutbound x 1,00x 1.00
fine settimanaWeekend giornodaytime in entratainbound x 1,00x 1.00
fine settimanaWeekend giornodaytime in uscitaoutbound x 1,00x 1.00
fine settimanaWeekend ore di punta seralievening rush in entratainbound x 1,00x 1.00
fine settimanaWeekend ore di punta seralievening rush in uscitaoutbound x 1,00x 1.00
fine settimanaWeekend notteovernight in entratainbound x 1,00x 1.00
fine settimanaWeekend notteovernight in uscitaoutbound x 1,00x 1.00

Sono presenti 16 combinazioni diverse delle tre variabili.There are 16 different combinations of the three variables. Combinando alcune delle condizioni, si semplificherà l'espressione switch finale.By combining some of the conditions, you'll simplify the final switch expression.

Il sistema che raccoglie i pedaggi usa una struttura DateTime per l'ora in cui il pedaggio è stato riscosso.The system that collects the tolls uses a DateTime structure for the time when the toll was collected. Compilare metodi membro che creano le variabili dalla tabella precedente.Build member methods that create the variables from the preceding table. La funzione seguente usa come criterio di ricerca l'espressione switch per esprimere se DateTime rappresenta il fine settimana o un giorno feriale:The following function uses a pattern matching switch expression to express whether a DateTime represents a weekend or a weekday:

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 funziona, ma è ripetitivo.That method works, but it's repetitious. È possibile semplificarlo, come illustrato nel codice seguente:You can simplify it, as shown in the following code:

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:Next, add a similar function to categorize the time into the blocks:

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

private static TimeBand GetTimeBand(DateTime timeOfToll)
{
    int hour = timeOfToll.Hour;
    if (hour < 6)
        return TimeBand.Overnight;
    else if (hour < 10)
        return TimeBand.MorningRush;
    else if (hour < 16)
        return TimeBand.Daytime;
    else if (hour < 20)
        return TimeBand.EveningRush;
    else
        return TimeBand.Overnight;
}

Il metodo precedente non usa criteri di ricerca.The previous method doesn't use pattern matching. Risulta più chiaro se si usa una familiare cascata di istruzioni if.It's clearer using a familiar cascade of if statements. Si aggiunge un elemento enum privato per convertire ogni intervallo di tempo in un valore discreto.You do add a private enum to convert each range of time to a discrete value.

Dopo aver creato tali metodi, è possibile usare un'altra espressione switch con il criterio di tupla per calcolare il sovrapprezzo.After you create those methods, you can use another switch expression with the tuple pattern to calculate the pricing premium. È possibile creare un'espressione switch con tutti i 16 elementi:You could build a switch expression with all 16 arms:

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.The above code works, but it can be simplified. Tutte le otto combinazioni per il fine settimana hanno lo stesso pedaggio.All eight combinations for the weekend have the same toll. È possibile sostituire tutte le otto combinazioni con la sola riga seguente:You can replace all eight with the following line:

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

Sia traffico in entrata che quello in uscita hanno lo stesso moltiplicatore durante le ore diurne e notturne dei giorni feriali.Both inbound and outbound traffic have the same multiplier during the weekday daytime and overnight hours. Questi quattro elementi possono essere sostituiti con le due righe seguenti:Those four switch arms can be replaced with the following two lines:

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

Dopo le due modifiche, il codice dovrebbe essere simile al seguente:The code should look like the following code after those two changes:

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.Finally, you can remove the two rush hour times that pay the regular price. Dopo aver rimosso tali elementi, è possibile sostituire false con un discard (_) nell'elemento switch finale.Once you remove those arms, you can replace the false with a discard (_) in the final switch arm. Il metodo finale sarà il seguente:You'll have the following finished method:

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 dei criteri di ricerca. I rami dei criteri vengono infatti valutati in ordine.This example highlights one of the advantages of pattern matching: the pattern branches are evaluated in order. Se si modifica l'ordine in modo che un ramo precedente gestisce uno dei case successivi, il compilatore avvisa l'utente perché il codice non è raggiungibile.If you rearrange them so that an earlier branch handles one of your later cases, the compiler warns you about the unreachable code. Grazie alle regole del linguaggio, è stato più facile eseguire le semplificazioni precedenti con la certezza che il codice non fosse modificato.Those language rules made it easier to do the preceding simplifications with confidence that the code didn't change.

I criteri di ricerca rendono alcuni tipi di codice più leggibili e costituiscono un'alternativa a tecniche orientate a oggetti quando non è possibile aggiungere codice alle classi.Pattern matching makes some types of code more readable and offers an alternative to object-oriented techniques when you can't add code to your classes. Nel cloud i dati e le funzionalità sono separati.The cloud is causing data and functionality to live apart. La forma dei dati e le operazioni su di essi non sono necessariamente descritte insieme.The shape of the data and the operations on it aren't necessarily described together. In questa esercitazione i dati esistenti sono stati utilizzati in modi completamente diversi dalla funzione originale.In this tutorial, you consumed existing data in entirely different ways from its original function. I criteri di ricerca hanno consentito di scrivere funzionalità che hanno eseguito l'override di tali tipi, anche se non è stato possibile estenderli.Pattern matching gave you the ability to write functionality that overrode those types, even though you couldn't extend them.

Passaggi successiviNext steps

È possibile scaricare il codice completo dal repository GitHub dotnet/samples.You can download the finished code from the dotnet/samples GitHub repository. Esplorare i criteri in autonomia e aggiungere questa tecnica alle normali attività di codifica.Explore patterns on your own and add this technique into your regular coding activities. L'apprendimento di queste tecniche offre un altro modo per affrontare i problemi e creare nuove funzionalità.Learning these techniques gives you another way to approach problems and create new functionality.