Modelli di tipo

Tip

Questo articolo fa parte della sezione Nozioni fondamentali per gli sviluppatori che già conoscono almeno un linguaggio di programmazione e stanno imparando C#. Iniziate con la panoramica della corrispondenza dei modelli se non conoscete ancora i modelli. Per le regole di compatibilità complete, vedere modelli di dichiarazione e tipi nel riferimento al linguaggio.

Un pattern di tipo si applica a un'espressione di input. C# valuta l'espressione, quindi verifica se il valore risultante è diverso da Null e il relativo tipo di runtime è compatibile con il tipo specificato. Un modello di tipo indica solo se il test di tipo ha esito positivo. Non dichiara una variabile.

Porre una domanda di tipo yes-or-no

In un sistema di consegna, IRouteStop è un contratto sulle capacità per le destinazioni accettate dalla pianificazione del percorso. CanRoute verifica se la destinazione valutata ha tale funzionalità e il relativo risultato booleano determina se la destinazione entra nel flusso di lavoro di pianificazione della route. Il flusso di lavoro richiede solo una risposta sì o no e non legge alcun membro route-stop, quindi va bene un pattern di tipo senza una variabile catturata.

static bool CanRoute(object? destination) =>
    destination is IRouteStop;

L'espressione di input è destinatione IRouteStop è il tipo sottoposto a test. Scegliere un modello di tipo quando la risposta è solo sì o no. Se il ramo corrispondente deve leggere un indirizzo o chiamare un altro membro tramite IRouteStop, scegliere invece un modello di dichiarazione in modo che il ramo disponga di una variabile di tale tipo.

Note

Potresti anche visualizzare destination is IRouteStop _. Tale sintassi è un modello di dichiarazione in cui _ non viene mantenuta alcuna variabile. Esegue lo stesso test di tipo quando entrambi i moduli sono validi, ma destination is IRouteStop indica più direttamente la finalità di sola prova.

Associare classi e interfacce

Nel sistema di distribuzione, IRouteStop definisce il contratto di capacità per le destinazioni della pianificazione del percorso, mentre RouteStop è una classe di base che fornisce dati e implementazione comuni delle fermate del percorso. ExpressRouteStop è una classe specializzata derivata da RouteStop. Nell'esempio viene verificato un valore valutato in modo che l'output possa dimostrare tutti e tre i tipi compatibili. Ogni test richiede solo un risultato booleano, quindi non è necessaria alcuna variabile acquisita.

interface IRouteStop { }

abstract class RouteStop(string street) : IRouteStop
{
    public string Street { get; } = street;

    public string GetDisplayName() => Street;
}

sealed class ExpressRouteStop(string street) : RouteStop(street)
{
}

static void ShowCompatibility()
{
    object destination = new ExpressRouteStop("8 Oak Avenue");

    Console.WriteLine($"Exact class: {destination is ExpressRouteStop}");
    Console.WriteLine($"Base class: {destination is RouteStop}");
    Console.WriteLine($"Interface: {destination is IRouteStop}");
}

Il valore valutato è un ExpressRouteStop. L'output mostra che corrisponde alla sua classe esatta, alla sua classe di base RouteStop e all'interfaccia IRouteStop che RouteStop implementa.

Per informazioni dettagliate sulle regole di compatibilità e sui casi limite, vedere le informazioni di riferimento sul modello di tipo.

Instradare più tipi

In un sistema di supporto è SupportRequest la classe base per classi di richieste specializzate, PasswordResetRequest ad esempio e BillingQuestion. Un ramo switch associa un pattern al risultato da restituire quando il pattern corrisponde. Ogni ramo restituisce il nome di una coda di elaborazione e il ramo finale fornisce una coda di riserva per gli altri valori valutati. La coda selezionata dipende solo dal tipo di runtime del valore valutato, quindi i modelli di tipo sono adatti perché non viene letto alcun membro della richiesta.

static string RouteRequest(object request) =>
    request switch
    {
        PasswordResetRequest => "Identity queue",
        BillingQuestion => "Billing queue",
        SupportRequest => "General support queue",
        _ => "Intake queue"
    };

Ogni arm risponde a una domanda di tipo e restituisce la coda che gestisce la richiesta. Se un ramo deve leggere gli elementi della richiesta, utilizzare un pattern di dichiarazione per assegnare il valore corrispondente a una variabile.

I bracci dello switch vengono considerati dall'alto al basso. Inserire una classe specializzata prima della relativa classe di base. In caso contrario, il braccio della classe base può corrispondere a ogni istanza della classe specializzata, che rende il braccio successivo non raggiungibile.

Facoltativo: usare un parametro di tipo come tipo testato

Questo esempio facoltativo si basa su tipi e metodi generici. Un parametro di tipo , TRequest ad esempio, è un segnaposto per un tipo fornito dal chiamante. Un batch di richieste in ingresso può contenere diversi tipi di richiesta e il chiamante fornisce ConfidentialRequest per verificare se una richiesta richiede la gestione riservata. Il risultato booleano seleziona la gestione riservata per l'intero batch e genera un messaggio di stato visibile. Un criterio di tipo con un parametro di tipo si adatta perché è importante solo l'esistenza di una richiesta corrispondente, quindi non è necessario conservare l'oggetto corrispondente.

static void ShowConfidentialBatchHandling()
{
    object[] incomingRequests = [new BillingQuestion(), new ConfidentialRequest()];
    bool requiresConfidentialHandling =
        ContainsRequestOfType<ConfidentialRequest>(incomingRequests);

    Console.WriteLine(requiresConfidentialHandling
        ? "Send the entire batch to confidential handling."
        : "Send the batch to standard handling.");
}

static bool ContainsRequestOfType<TRequest>(IEnumerable<object> requests)
{
    foreach (object request in requests)
    {
        if (request is TRequest)
        {
            return true;
        }
    }

    return false;
}

Se il chiamante necessita della richiesta corrispondente stessa, un'operazione di ricerca o filtro che restituisce gli elementi corrispondenti sarebbe più appropriata.

Vedi anche