Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
À compter de C# 15, vous pouvez appliquer le closed modificateur à une classe pour déclarer une hiérarchie fermée. Vous ne pouvez dériver qu’un sous-type direct d’une classe fermée dans son assembly déclarant. Étant donné que l’ensemble de descendants directs est fixe, une switch expression qui gère chaque descendant direct épuise le type de base fermé et n’a pas besoin d’un bras par défaut.
// Assembly 1
public closed record class JobStatus;
public record class Queued : JobStatus;
public record class Running(int PercentComplete) : JobStatus;
public record class Completed(TimeSpan Elapsed) : JobStatus;
public record class Failed(string Error) : JobStatus;
// Assembly 2
public record class Paused : JobStatus; // Error: 'JobStatus' is a closed class
La restriction de même assembly s’applique uniquement aux descendants directs de la classe fermée. Une classe qui dérive d’une classe fermée n’est pas elle-même fermée, sauf si vous la closedmarquez également. Dans Failed l’exemple précédent étant un enregistrement brut, un autre assembly peut dériver de celui-ci :
// Assembly 2
public record class RetryableFailed(string Error, int Attempts) : Failed(Error); // OK: 'Failed' isn't sealed or closed
Si vous souhaitez également empêcher la dérivation Failed , déclarez-la en tant que sealed ou closed.
La documentation de référence du langage C# décrit la version la plus récente du langage C#. Il contient également la documentation initiale des fonctionnalités dans les préversions publiques pour la prochaine version du langage.
La documentation identifie toute fonctionnalité introduite en premier dans les trois dernières versions de la langue ou dans les préversions publiques actuelles.
Tip
Pour savoir quand une fonctionnalité a été introduite en C#, consultez l’article sur l’historique des versions du langage C#.
Note
closed est un mot clé contextuel. Il a une signification particulière uniquement lorsqu’il apparaît en tant que modificateur sur une déclaration de classe. Vous pouvez continuer à utiliser closed comme identificateur dans d’autres contextes. Si vous devez utiliser closed comme identificateur dans une position où le modificateur serait également valide, préfixez-le ( @ par exemple @closed) pour indiquer au compilateur de le traiter comme un identificateur plutôt que le modificateur.
Règles de déclaration
Le closed modificateur est un modificateur de classe :
- Une
closedclasse est implicitementabstract. Vous ne pouvez pas combinerclosedavecsealed,staticou un modificateur expliciteabstract. - Vous devez déclarer un sous-type direct d’une classe fermée dans le même assembly et le même module que la classe de base fermée.
- Une classe qui dérive d’une classe fermée n’est pas elle-même fermée. Appliquez à nouveau le
closedmodificateur si vous souhaitez qu’une classe dérivée soit également fermée.
Si une classe générique dérive directement d’une closed classe, chaque paramètre de type de la classe dérivée doit être utilisé dans la spécification de classe de base. Cette règle ne concerne pas le closed modificateur lui-même : un type construit fermé est un type générique dont les arguments de type sont entièrement spécifiés (par exemple Tree<int>), par opposition à un type ouvert comme Tree<T>. La règle garantit que chaque type construit fermé de la classe de base a exactement un type construit fermé correspondant parmi ses descendants directs, afin que le compilateur puisse raisonner sur l’exhaustivité.
public closed record class Tree<T>;
public record class Leaf<T>(T Value) : Tree<T>; // OK: 'T' appears in the base class
public record class Branch<T>(Tree<T> Left, Tree<T> Right) : Tree<T>; // OK: 'T' appears in the base class
public record class Constant<U>(U Value) : Tree<int> { } // Error: 'U' isn't used in the base class
Expressions de commutateur exhaustives
Lorsqu’une switch expression gère chaque descendant direct d’une classe fermée, le compilateur considère le commutateur exhaustive et ne génère pas d’avertissement d’absence d’exhaustive :
public static string Describe(JobStatus status) => status switch
{
Queued => "waiting to start",
Running(var percent) => $"{percent}% complete",
Completed(var elapsed) => $"finished in {elapsed.TotalSeconds:F1}s",
Failed(var error) => $"failed: {error}",
// No warning: every direct descendant of 'JobStatus' is handled.
};
Lorsque l’expression de gouvernance du commutateur est nullable, null devient une autre valeur possible que le commutateur doit gérer. Un basculement JobStatus? n’est exhaustif que lorsqu’il couvre nullégalement :
public static string DescribeOrUnknown(JobStatus? status) => status switch
{
null => "unknown",
Queued => "waiting to start",
Running(var percent) => $"{percent}% complete",
Completed(var elapsed) => $"finished in {elapsed.TotalSeconds:F1}s",
Failed(var error) => $"failed: {error}",
// No warning: every direct descendant of 'JobStatus' is handled, and null is handled.
};
Si vous omettez le null bras, le compilateur avertit que le modèle null n’est pas géré. La même règle s’applique si le type fermé est une classe ou un struct levé vers un type Nullable.
Pour plus d’informations sur la façon dont le compilateur détermine l’exhaustivité, notamment la façon dont les hiérarchies fermées interagissent avec les contraintes génériques et l’accessibilité, consultez modèles de hiérarchie fermée.
Paramètres de type contraints à un type fermé
Un paramètre de type limité à une classe fermée est traité comme cette classe fermée pour des vérifications exhaustives. Expression switch dont la valeur de gouvernance a un tel paramètre de type est exhaustive lorsqu’elle gère chaque descendant direct de la contrainte fermée :
public static string DescribeJob<X>(X status) where X : JobStatus => status switch
{
Queued => "waiting to start",
Running(var percent) => $"{percent}% complete",
Completed(var elapsed) => $"finished in {elapsed.TotalSeconds:F1}s",
Failed(var error) => $"failed: {error}",
// No warning: 'X' is constrained to a closed type, so its direct descendants exhaust the switch.
};
Cette règle s’applique si le paramètre de type apparaît sur une méthode ou sur le type conteneur.
Spécification du langage C#
Pour plus d’informations, consultez la spécification de la fonctionnalité Hiérarchies fermées .