Modèles de type

Tip

Cet article fait partie de la section Notions de base pour les développeurs qui connaissent déjà au moins un langage de programmation et apprennent C#. Commencez par la vue d’ensemble des critères correspondants si les modèles sont nouveaux pour vous. Pour obtenir des règles de compatibilité complètes, consultez les modèles de déclaration et de type dans la référence de langage.

Un modèle de type est appliqué à une expression d’entrée. C# évalue l’expression, puis teste si la valeur résultante n’est pas null et que son type d’exécution est compatible avec le type spécifié. Un modèle de type indique uniquement si le test de type réussit. Elle ne déclare pas de variable.

Poser une question de type oui-or-no

Dans un système de livraison, IRouteStop il s’agit d’un contrat de capacité pour les destinations acceptées par la planification des itinéraires. CanRoute teste si la destination évaluée a cette fonctionnalité et son résultat booléen détermine si la destination entre dans le flux de travail de planification de l’itinéraire. Le flux de travail a seulement besoin d’une réponse par oui ou par non et ne lit aucun membre de type route-stop ; un modèle de type sans variable capturée convient donc.

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

L’expression d’entrée est destination, et IRouteStop est le type testé. Choisissez un modèle de type lorsque la réponse est uniquement oui ou non. Si la branche correspondante doit lire une adresse ou appeler un autre membre via IRouteStop, choisissez plutôt un modèle de déclaration afin que la branche ait une variable de ce type.

Note

Vous pouvez également voir destination is IRouteStop _. Cette syntaxe est un modèle de déclaration dans lequel _ aucune variable n’est conservée. Il effectue le même test de type lorsque les deux formulaires sont valides, mais destination is IRouteStop indique l’intention de test uniquement plus directement.

Mettre en correspondance des classes et des interfaces

Dans le système de livraison, IRouteStop définit le contrat de capacité pour les destinations de planification des itinéraires, tandis qu’il RouteStop s’agit d’une classe de base qui fournit des données et une implémentation courantes d’arrêt de routage. ExpressRouteStop est une classe spécialisée dérivée de RouteStop. L’exemple teste une valeur évaluée afin que sa sortie puisse illustrer les trois types compatibles. Chaque test n’a besoin que d’un résultat booléen, donc aucune variable capturée n’est nécessaire.

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}");
}

La valeur évaluée est un ExpressRouteStop. La sortie indique qu’elle correspond à sa classe exacte, à sa RouteStop classe de base et à l’interface IRouteStop qui RouteStop implémente.

Pour obtenir des règles de compatibilité détaillées et des cas de périphérie, consultez la référence du modèle de type.

Router plusieurs types

Dans un système de support, SupportRequest est la classe de base pour les classes de requête spécialisées telles que PasswordResetRequest et BillingQuestion. Une branche de switch associe un motif au résultat à renvoyer lorsque ce motif correspond. Chaque branche renvoie le nom d’une file d’attente de traitement, et la dernière branche spécifie une file d’attente de repli pour les autres valeurs évaluées. La file d’attente sélectionnée dépend uniquement du type d’exécution de la valeur évaluée. Par conséquent, les modèles de type correspondent, car aucun membre de demande n’est lu.

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

Chaque branche répond à une question sur le type et renvoie la file d’attente qui gère cette requête. Si une branche doit lire les éléments de la requête, utilisez un motif de déclaration pour capturer la valeur correspondante dans une variable.

Les bras de commutateur sont pris en compte de haut en bas. Placez une classe spécialisée avant sa classe de base. Sinon, la branche de la classe de base peut correspondre à toutes les instances de la classe spécialisée, ce qui rend la branche suivante inatteignable.

Facultatif : utiliser un paramètre de type comme type testé

Cet exemple facultatif s’appuie sur des types et méthodes génériques. Un paramètre de type comme TRequest est un espace réservé pour un type fourni par l’appelant. Un lot de demandes entrantes peut contenir plusieurs types de requêtes et l’appelant fournit ConfidentialRequest pour tester si une demande nécessite une gestion confidentielle. Le résultat booléen sélectionne la gestion confidentielle pour l’ensemble du lot et produit un message d’état visible. Un modèle de type avec un paramètre de type s’adapte car seule l’existence d’une demande correspondante importe, de sorte que l’objet correspondant n’a pas besoin d’être conservé.

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;
}

Si l’appelant a besoin de la demande correspondante elle-même, une opération de recherche ou de filtre qui retourne des éléments correspondants serait plus appropriée.

Voir aussi