Partage via


11 Modèles et correspondances de modèles

11.1 Général

Un modèle est un formulaire syntactique qui peut être utilisé avec l’opérateur is (§12.12.12) et dans un switch_statement (§13.8.3) pour exprimer la forme de données par rapport à laquelle les données entrantes doivent être comparées. Un modèle est testé par rapport à l’expression d’une instruction switch ou à une relational_expression qui se trouve sur le côté gauche d’un is opérateur, chacun d’eux étant appelé valeur d’entrée de modèle.

11.2 Formulaires de modèle

11.2.1 Général

Un modèle peut avoir l’une des formes suivantes :

pattern
    : declaration_pattern
    | constant_pattern
    | var_pattern
    ;

Une declaration_pattern et une var_pattern peuvent entraîner la déclaration d’une variable locale.

Chaque formulaire de modèle définit l’ensemble de types pour les valeurs d’entrée auxquelles le modèle peut être appliqué. Un modèle P s’applique à un type T s’il T se trouve parmi les types dont les valeurs peuvent correspondre au modèle. Il s’agit d’une erreur au moment de la compilation si un modèle P apparaît dans un programme pour correspondre à une valeur d’entrée de modèle (§11.1) du type T s’il P n’est pas applicable.T

Exemple : l’exemple suivant génère une erreur au moment de la compilation, car le type de compilation est vTextReader. Une variable de type TextReader ne peut jamais avoir de valeur compatible référence avec string:

TextReader v = Console.In; // compile-time type of 'v' is 'TextReader'
if (v is string) // compile-time error
{
    // code assuming v is a string
}

Toutefois, les éléments suivants ne génèrent pas d’erreur au moment de la compilation, car le type de compilation est vobject. Une variable de type object peut avoir une valeur compatible référence avec string:

object v = Console.In;
if (v is string s)
{
    // code assuming v is a string
}

exemple de fin

Chaque formulaire de modèle définit l’ensemble de valeurs pour lesquelles le modèle correspond à la valeur au moment de l’exécution.

Modèle de déclaration 11.2.2

Une declaration_pattern est utilisée pour tester qu’une valeur a un type donné et, si le test réussit, fournissez la valeur dans une variable de ce type.

declaration_pattern
    : type simple_designation
    ;
simple_designation
    : single_variable_designation
    ;
single_variable_designation
    : identifier
    ;

Le type d’exécution de la valeur est testé par rapport au type dans le modèle à l’aide des mêmes règles spécifiées dans l’opérateur is-type (§12.12.12.12.1). Si le test réussit, le modèle correspond à cette valeur. Il s’agit d’une erreur au moment de la compilation si le type est un type valeur nullable (§8.3.12). Ce formulaire de modèle ne correspond jamais à une null valeur.

Remarque : L’expression e is T is-type et le modèle e is T _ de déclaration sont équivalents lorsqu’il T n’est pas un type Nullable. Note de fin

Étant donné une valeur d’entrée de modèle (§11.1) e, si le simple_designation est l’identificateur_, cela indique un rejet (§9.2.9.2) et la valeur de e n’est liée à rien. (Bien qu’une variable déclarée portant le nom _ puisse être dans l’étendue à ce stade, cette variable nommée n’est pas vue dans ce contexte.) Si simple_designation est un autre identificateur, une variable locale (§9.2.9.1) du type donné nommé par l’identificateur donné est introduite. Cette variable locale est affectée à la valeur d’entrée du modèle lorsque le modèle correspond à la valeur.

Certaines combinaisons de type statique de la valeur d’entrée du modèle et du type donné sont considérées comme incompatibles et entraînent une erreur au moment de la compilation. Une valeur de type E statique est considérée comme compatible avec le type T s’il existe une conversion d’identité, une conversion de référence implicite ou explicite, une conversion de boxe ou une conversion d’unboxing à Epartir T de , ou s’il ET s’agit d’un type ouvert (§8.4.3). Un modèle de déclaration nommant un type s’applique T chaque type pour lequel E le modèle est compatible avec E.T

Remarque : La prise en charge des types ouverts peut être la plus utile lors de la vérification des types qui peuvent être des types de structure ou de classe, et la boxe doit être évitée. Note de fin

Exemple : Le modèle de déclaration est utile pour effectuer des tests de type d’exécution de types référence et remplacer l’idiome

var v = expr as Type;
if (v != null) { /* code using v */ }

avec le plus concis

if (expr is Type v) { /* code using v */ }

exemple de fin

Il s’agit d’une erreur si le type est un type valeur nullable.

Exemple : le modèle de déclaration peut être utilisé pour tester des valeurs de types Nullables : une valeur de type Nullable<T> (ou une zone T) correspond à un modèle T2 id de type si la valeur est non null et T2 est T, ou un type de base ou une interface de T. Par exemple, dans le fragment de code

int? x = 3;
if (x is int v) { /* code using v */ }

La condition de l’instruction est if au moment de l’exécution true et la variable v contient la valeur 3 du type int à l’intérieur du bloc. exemple de fin

Modèle de constante 11.2.3

Un constant_pattern est utilisé pour tester la valeur d’une valeur d’entrée de modèle (§11.1) par rapport à la valeur constante donnée.

constant_pattern
    : constant_expression
    ;

Un modèle P constant s’applique à un type T s’il existe une conversion implicite de l’expression constante du P type T.

Pour un modèle Pconstant, sa valeur convertie est

  • si le type de la valeur d’entrée de modèle est un type intégral ou un type d’énumération, la valeur constante du modèle convertie en ce type ; autrement
  • si le type de la valeur d’entrée de modèle est la version nullable d’un type intégral ou d’un type enum, la valeur constante du modèle convertie en son type sous-jacent ; autrement
  • valeur de la valeur constante du modèle.

Compte tenu d’une valeur d’entrée de modèle e et d’un modèle P constant avec la valeur convertie v,

  • si e a un type intégral ou un type enum, ou une forme Nullable d’un de ces types, et v a un type intégral, le modèle Pcorrespond à la valeur e si le résultat de l’expression e == v est true; sinon,
  • le modèle Pcorrespond à la valeur e si object.Equals(e, v) elle est retournée true.

Exemple : L’instruction switch de la méthode suivante utilise cinq modèles constants dans ses étiquettes de cas.

static decimal GetGroupTicketPrice(int visitorCount)
{
    switch (visitorCount) 
    {
        case 1: return 12.0m;
        case 2: return 20.0m;
        case 3: return 27.0m;
        case 4: return 32.0m;
        case 0: return 0.0m;
        default: throw new ArgumentException(...);
    }
}

exemple de fin

Modèle var 11.2.4

Une var_patterncorrespond à chaque valeur. Autrement dit, une opération de correspondance de modèle avec un var_pattern réussit toujours.

Une var_pattern s’applique à chaque type.

var_pattern
    : 'var' designation
    ;
designation
    : simple_designation
    ;

Étant donné une valeur d'entrée de modèle (§11.1) e, si la désignation est l'identificateur _, cela indique un abandon (§9.2.9.2), et la valeur de e n'est liée à rien. (Bien qu’une variable déclarée portant ce nom puisse être dans l’étendue à ce stade, cette variable nommée n’est pas vue dans ce contexte.) Si désignation est un autre identificateur, au moment de l’exécution, la valeur de e est liée à une variable locale nouvellement introduite (§9.2.9.1) de ce nom dont le type est le type statique de e, et la valeur d’entrée du modèle est affectée à cette variable locale.

Il s’agit d’une erreur si le nom var est lié à un type où un var_pattern est utilisé.

11.3 Sous-énumération du modèle

Dans une instruction switch, il s’agit d’une erreur si le modèle d’un cas est subsumé par l’ensemble précédent de cas non surveillés (§13.8.3). De façon informelle, cela signifie que toute valeur d’entrée aurait été mise en correspondance par l’un des cas précédents. Les règles suivantes définissent lorsqu’un ensemble de modèles subsume un modèle donné :

Un modèle Pcorrespond à une constante K si la spécification du comportement d’exécution de ce modèle correspond à Pcelle-ci K .

Un ensemble de modèles Qsubsume un modèle P si l’une des conditions suivantes est en attente :

11.4 Exhaustive des modèles

De façon informelle, un ensemble de modèles est exhaustif pour un type si, pour chaque valeur possible de ce type autre que null, certains modèles de l’ensemble sont applicables. Les règles suivantes définissent lorsqu’un ensemble de modèles est exhaustif pour un type :

Un ensemble de modèles Q est exhaustif pour un type T si l’une des conditions suivantes est conservée :

  1. T est un type intégral ou enum, ou une version nullable de l’un de ces éléments, et pour chaque valeur possible du Ttype sous-jacent non nullable, un modèle dans lequel Q il correspondrait à cette valeur ; ou
  2. Certains modèles sont Q un modèle var ; ou
  3. Certains modèles sont Q un modèle de déclaration pour le typeD, et il existe une conversion d’identité, une conversion de référence implicite ou une conversion de boxe à Tpartir de D .

Exemple :

static void M(byte b)
{
    switch (b) {
        case 0: case 1: case 2: ... // handle every specific value of byte
            break;
        // error: the pattern 'byte other' is subsumed by the (exhaustive)
        // previous cases
        case byte other: 
            break;
    }
}

exemple de fin