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
v
TextReader
. Une variable de typeTextReader
ne peut jamais avoir de valeur compatible référence avecstring
: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
v
object
. Une variable de typeobject
peut avoir une valeur compatible référence avecstring
: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èlee is T _
de déclaration sont équivalents lorsqu’ilT
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 à E
partir T
de , ou s’il E
T
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 zoneT
) correspond à un modèleT2 id
de type si la valeur est non null etT2
estT
, ou un type de base ou une interface deT
. Par exemple, dans le fragment de codeint? x = 3; if (x is int v) { /* code using v */ }
La condition de l’instruction est
if
au moment de l’exécutiontrue
et la variablev
contient la valeur3
du typeint
à 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 P
constant, 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
P
correspond à la valeur e si le résultat de l’expressione == v
esttrue
; sinon, - le modèle
P
correspond à la valeur e siobject.Equals(e, v)
elle est retournéetrue
.
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 P
correspond à une constante K
si la spécification du comportement d’exécution de ce modèle correspond à P
celle-ci K
.
Un ensemble de modèles Q
subsume un modèle P
si l’une des conditions suivantes est en attente :
P
est un modèle constant et l’un des modèles de l’ensemble correspondraitQ
à la valeur convertie de l’ensembleP
P
est un modèle var et l’ensemble de modèles est exhaustif (§11.4) pour le type de la valeur d’entrée du modèle (Q
), et soit la valeur d’entrée du modèle n’est pas d’un type Nullable ou d’un modèle correspondant .Q
null
P
est un modèle de déclaration avec typeT
et l’ensemble de modèlesQ
est exhaustif pour le typeT
(§11.4).
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 :
T
est un type intégral ou enum, ou une version nullable de l’un de ces éléments, et pour chaque valeur possible duT
type sous-jacent non nullable, un modèle dans lequelQ
il correspondrait à cette valeur ; ou- Certains modèles sont
Q
un modèle var ; ou - 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 àT
partir deD
.
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
ECMA C# draft specification