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.
11.1 Général
Un modèle est une forme syntactique qui peut être utilisée avec l’opérateur is (§12.15.12), dans un switch_statement (§13.8.3) et dans un switch_expression (§12.12) pour exprimer la forme de données sur laquelle les données entrantes doivent être comparées. Les modèles peuvent être récursifs, de sorte que les parties des données peuvent être mises en correspondance par rapport aux sous-modèles.
Un modèle est testé par rapport à une valeur dans un certain nombre de contextes :
- Dans une instruction switch, le modèle d’une étiquette de casse est testé par rapport à l’expression de l’instruction switch.
- Dans un opérateur is-pattern , le modèle situé à droite est testé par rapport à l’expression située à gauche.
- Dans une expression switch, le modèle d’un switch_expression_arm est testé par rapport à l’expression sur le côté gauche de l’expression switch-expression.
- Dans les contextes imbriqués, le sous-modèle est testé par rapport aux valeurs récupérées à partir de propriétés, de champs ou indexées à partir d’autres valeurs d’entrée, en fonction du formulaire de modèle.
La valeur par rapport à laquelle un modèle est testé est appelée 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
: logical_pattern
;
primary_pattern
: parenthesized_pattern
| declaration_pattern
| constant_pattern
| var_pattern
| positional_pattern
| property_pattern
| discard_pattern
| type_pattern
| relational_pattern
;
parenthesized_pattern
: '(' pattern ')'
;
La '(' pattern ')' production permet à un modèle d’être placé entre parenthèses pour appliquer l’ordre d’évaluation entre les modèles combinés à l’aide de l’un des logical_patterns.
Certains modèlespeuvent 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 typeTextReaderne 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
vobject. Une variable de typeobjectpeut 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.
L’ordre d’évaluation des opérations et des effets secondaires pendant la correspondance des modèles (appels aux Deconstructaccès aux propriétés et appels de méthodes dans System.ITuple) n’est pas spécifié.
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, pour fournir éventuellement la valeur dans une variable de ce type.
declaration_pattern
: type simple_designation
;
simple_designation
: discard_designation
| single_variable_designation
;
discard_designation
: '_'
;
single_variable_designation
: identifier
;
Une simple_designation avec le jeton _ doit être considérée comme une discard_designation plutôt qu’une single_variable_designation.
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.15.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) ou un type référence nullable (§8.9.3). Ce formulaire de modèle ne correspond jamais à une null valeur.
Remarque : L’expression
e is Tis-type et le modèlee is T _de déclaration sont équivalents lorsqu’ilTn’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 discard_designation, il désigne un abandon (§9.2.9.2) et la valeur 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.) Sinon, si le simple_designation est single_variable_designation, une variable locale (§9.2.9) 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 un modèle 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, une conversion unboxing ou une conversion implicite ou explicite de type valeur nullable de E vers T, ou si ET 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
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 idde type si la valeur est non null etT2estT, 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
ifau moment de l’exécutiontrueet la variablevcontient la valeur3du typeintà l’intérieur du bloc. Une fois que le bloc de la variablevest dans l’étendue, mais pas définitivement affecté. 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’expressione == vesttrue; sinon, - le modèle
Pcorrespond à la valeur e siobject.Equals(e, v)elle est retournéetrue.
Exemple : L’instruction
switchde 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
| tuple_designation
;
tuple_designation
: '(' designations? ')'
;
designations
: designation (',' designation)*
;
Étant donné une valeur d’entrée de modèle (§11.1) e, si la désignation est discard_designation, elle désigne un abandon (§9.2.9.2) et la valeur 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.) Sinon, si la désignation est single_variable_designation, au moment de l’exécution, la valeur e est liée à une variable locale nouvellement introduite (§9.2.9) 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é.
Si la désignation est un tuple_designation, le modèle équivaut à un positional_pattern (§11.2.5) de la (var de formulaire, ...
) où les désignationssont celles trouvées dans la tuple_designation. Par exemple, le modèle var (x, (y, z)) est équivalent à (var x, (var y, var z)).
11.2.5 Modèle positionnel
Un positional_pattern vérifie que la valeur d’entrée n’est pas null, appelle une méthode appropriée Deconstruct (§12.7) et effectue une correspondance de modèle supplémentaire sur les valeurs résultantes. Il prend également en charge une syntaxe de modèle de type tuple (sans le type fourni) lorsque le type de la valeur d’entrée est identique au type contenant Deconstruct, ou si le type de la valeur d’entrée est un type tuple, ou si le type de la valeur d’entrée est object ou System.ITuple si le type d’exécution de l’expression implémente System.ITuple.
positional_pattern
: type? '(' subpatterns? ')' property_subpattern? simple_designation?
;
subpatterns
: subpattern (',' subpattern)*
;
subpattern
: pattern
| identifier ':' pattern
;
Étant donné une correspondance d’une valeur d’entrée auxsous-modèles( de type de modèle), une méthode est sélectionnée en recherchant dans le type des déclarations accessibles et Deconstruct en sélectionnant une parmi elles à l’aide des mêmes règles que pour la déclaration de déconstruction.
Il s’agit d’une erreur si un positional_pattern omettre le type, a un sous-modèle unique sans identificateur, n’a aucun property_subpattern et n’a pas de simple_designation. Cela désambigue entre un constant_pattern entre parenthèses et un positional_pattern.
Pour extraire les valeurs à mettre en correspondance avec les modèles de la liste,
- Si le type est omis et que le type de l’expression d’entrée est un type tuple, le nombre de sous-modèles doit être identique à la cardinalité du tuple. Chaque élément tuple est mis en correspondance avec le sous-modèle correspondant, et la correspondance réussit si tous ces éléments réussissent. Si un sous-modèle a un identificateur, il doit nommer un élément tuple à la position correspondante dans le type tuple.
- Sinon, s’il existe un membre de
Deconstructapproprié, il s’agit d’une erreur au moment de la compilation si le type de la valeur d’entrée n’est pas compatible avec le type. Au moment de l’exécution, la valeur d’entrée est testée par rapport au type. Si cela échoue, la correspondance de modèle positionnel échoue. Si elle réussit, la valeur d’entrée est convertie en ce type etDeconstructest appelée avec de nouvelles variables générées par le compilateur pour recevoir les paramètres de sortie. Chaque valeur reçue est mise en correspondance avec le sous-modèle correspondant, et la correspondance réussit si toutes ces valeurs réussissent. Si un sous-modèle a un identificateur, celui-ci doit nommer un paramètre à la position correspondante deDeconstruct. - Sinon, si le type est omis, et que la valeur d’entrée est de type
objectou d’un type qui peut être convertiSystem.ITuplepar une conversion de référence implicite, et qu’aucun identificateur n’apparaît parmi les sous-modèles, la correspondance utiliseSystem.ITuple. - Sinon, le modèle est une erreur au moment de la compilation.
L’ordre dans lequel les sous-modèles sont mis en correspondance au moment de l’exécution n’est pas spécifié et une correspondance ayant échoué peut ne pas tenter de faire correspondre tous les sous-modèles.
Exemple : ici, nous déconstructons un résultat d’expression et correspondons aux valeurs obtenues par rapport aux modèles imbriqués correspondants :
static string Classify(Point point) => point switch { (0, 0) => "Origin", (1, 0) => "positive X basis end", (0, 1) => "positive Y basis end", _ => "Just a point", }; public readonly struct Point { public int X { get; } public int Y { get; } public Point(int x, int y) => (X, Y) = (x, y); public void Deconstruct(out int x, out int y) => (x, y) = (X, Y); }exemple de fin
Exemple : Les noms des éléments tuple et des paramètres de déconstruction peuvent être utilisés dans un modèle positionnel, comme suit :
var numbers = new List<int> { 10, 20, 30 }; if (SumAndCount(numbers) is (Sum: var sum, Count: var count)) { Console.WriteLine($"Sum of [{string.Join(" ", numbers)}] is {sum}"); } static (double Sum, int Count) SumAndCount(IEnumerable<int> numbers) { int sum = 0; int count = 0; foreach (int number in numbers) { sum += number; count++; } return (sum, count); }La sortie produite est
Sum of [10 20 30] is 60exemple de fin
Modèle de propriété 11.2.6
Une property_pattern vérifie que la valeur d’entrée n’est pas null, et correspond de manière récursive aux valeurs extraites par l’utilisation de propriétés ou de champs accessibles.
property_pattern
: type? property_subpattern simple_designation?
;
property_subpattern
: '{' '}'
| '{' subpatterns ','? '}'
;
Il s’agit d’une erreur si un sous-modèle d’un property_pattern ne contient pas d’identificateur.
Il s’agit d’une erreur au moment de la compilation si le type est un type valeur nullable (§8.3.12) ou un type référence nullable (§8.9.3).
Remarque : Un modèle de vérification null ne fait pas partie d’un modèle de propriété trivial. Pour vérifier si la chaîne
sn’est pas null, il est possible d’écrire l’une des formes suivantes :#nullable enable string s = "abc"; if (s is object o) ... // o is of type object if (s is string x1) ... // x1 is of type string if (s is {} x2) ... // x2 is of type string if (s is {}) ...Note de fin
Étant donné une correspondance d’une expression e auxsous-modèles{ de type de modèle}, il s’agit d’une erreur au moment de la compilation si l’expression e n’est pas compatible avec le type T désigné par type. Si le type est absent, le type est supposé être le type statique de e. Chacun des identificateurs apparaissant sur le côté gauche de ses sous-modèles doit désigner une propriété ou un champ accessible accessible en lecture de T. Si la simple_designation du property_pattern est présente, elle déclare une variable de modèle de type T.
Au moment de l’exécution, l’expression est testée sur T. Si cela échoue, la correspondance du modèle de propriété échoue et le résultat est false. Si elle réussit, chaque champ ou propriété property_subpattern est lu et sa valeur correspond à son modèle correspondant. Le résultat de la correspondance entière n’est false que si le résultat de l’un de ces résultats est false. L’ordre dans lequel les sous-modèles sont mis en correspondance n’est pas spécifié, et une correspondance ayant échoué peut ne pas tester tous les sous-modèles au moment de l’exécution. Si la correspondance réussit et que le simple_designation de l’property_pattern est un single_variable_designation, la variable déclarée est affectée à la valeur correspondante.
Le property_pattern peut être utilisé pour faire correspondre des modèles avec des types anonymes.
Exemple :
var o = ...; if (o is string { Length: 5 } s) ...exemple de fin
Exemple : une vérification de type d’exécution et une déclaration de variable peuvent être ajoutées à un modèle de propriété, comme suit :
Console.WriteLine(TakeFive("Hello, world!")); // output: Hello Console.WriteLine(TakeFive("Hi!")); // output: Hi! Console.WriteLine(TakeFive(new[] { '1', '2', '3', '4', '5', '6', '7' })); // output: 12345 Console.WriteLine(TakeFive(new[] { 'a', 'b', 'c' })); // output: abc static string TakeFive(object input) => input switch { string { Length: >= 5 } s => s.Substring(0, 5), string s => s, ICollection<char> { Count: >= 5 } symbols => new string(symbols.Take(5).ToArray()), ICollection<char> symbols => new string(symbols.ToArray()), null => throw new ArgumentNullException(nameof(input)), _ => throw new ArgumentException("Not supported input type."), };La sortie produite est
Hello Hi! 12345 abcexemple de fin
11.2.7 Modèle d’abandon
Chaque expression correspond au modèle d’abandon, ce qui entraîne l’abandon de la valeur de l’expression.
discard_pattern
: '_'
;
Il s’agit d’une erreur au moment de la compilation d’utiliser un modèle d’abandon dans un relational_expression du modèle relational_expressionisformulaire ou comme modèle d’un switch_label.
Remarque : Dans ces cas, pour correspondre à n’importe quelle expression, utilisez un var_pattern avec un abandon
var _. Note de fin
Exemple :
Console.WriteLine(GetDiscountInPercent(DayOfWeek.Friday)); Console.WriteLine(GetDiscountInPercent(null)); Console.WriteLine(GetDiscountInPercent((DayOfWeek)10)); static decimal GetDiscountInPercent(DayOfWeek? dayOfWeek) => dayOfWeek switch { DayOfWeek.Monday => 0.5m, DayOfWeek.Tuesday => 12.5m, DayOfWeek.Wednesday => 7.5m, DayOfWeek.Thursday => 12.5m, DayOfWeek.Friday => 5.0m, DayOfWeek.Saturday => 2.5m, DayOfWeek.Sunday => 2.0m, _ => 0.0m, };La sortie produite est
5.0 0.0 0.0Ici, un modèle d’abandon est utilisé pour gérer
nullet toute valeur entière qui n’a pas le membre correspondant de l’énumérationDayOfWeek. Cela garantit que l’expressionswitchgère toutes les valeurs d’entrée possibles. exemple de fin
Modèle de type 11.2.8
Une type_pattern est utilisée pour tester que la valeur d’entrée du modèle (§11.1) a un type donné.
type_pattern
: type
;
Un modèle de type nommant un type Ts’applique à chaque type E pour lequel E il est compatible avec T (§11.2.2).
Le type d’exécution de la valeur est testé par rapport au type à l’aide des mêmes règles spécifiées dans l’opérateur is-type (§12.15.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 Nullable. Ce formulaire de modèle ne correspond jamais à une null valeur.
11.2.9 Modèle relationnel
Une relational_pattern est utilisée pour tester relationnellement la valeur d’entrée du modèle (§11.1) par rapport à une valeur constante.
relational_pattern
: '<' relational_expression
| '<=' relational_expression
| '>' relational_expression
| '>=' relational_expression
;
La relational_expression dans un relational_pattern est nécessaire pour évaluer une valeur constante.
Les modèles relationnels prennent en charge les opérateurs <relationnels , ><=et >= sur tous les types intégrés qui prennent en charge ces opérateurs relationnels binaires avec les deux opérandes ayant le même type : sbyte, , byteshort, ushort, , , int, uint, floatnintulongnuintlongchardoubledecimalet enums.
Une relational_patterns’applique à un type T si un opérateur relationnel binaire intégré approprié est défini avec les deux opérandes de type T, ou si une conversion explicite nullable ou unboxing existe depuis T le type de l’expression constante.
Il s’agit d’une erreur au moment de la compilation si l’expression prend double.NaNla valeur , float.NaNou une constante Null.
Lorsque la valeur d’entrée a un type pour lequel un opérateur relationnel binaire intégré approprié est défini, l’évaluation de cet opérateur est considérée comme la signification du modèle relationnel. Sinon, la valeur d’entrée est convertie en type d’expression constante à l’aide d’une conversion explicite nullable ou unboxing. Il s’agit d’une erreur de compilation si aucune conversion de ce type n’existe. Le modèle est considéré comme ne correspondant pas si la conversion échoue. Si la conversion réussit, le résultat de l’opération de correspondance de modèle est le résultat de l’évaluation de l’expression e «op» v où e est l’entrée convertie, « op » est l’opérateur relationnel et v est l’expression constante.
Exemple :
Console.WriteLine(Classify(13)); Console.WriteLine(Classify(double.NaN)); Console.WriteLine(Classify(2.4)); static string Classify(double measurement) => measurement switch { < -4.0 => "Too low", > 10.0 => "Too high", double.NaN => "Unknown", _ => "Acceptable", };La sortie produite est
Too high Unknown Acceptableexemple de fin
Modèle logique 11.2.10
Une logical_pattern est utilisée pour négation du résultat d’une correspondance de modèle, ou pour combiner les résultats de plusieurs correspondances de modèle à l’aide de la conjonction (and) ou de la disjonction (or).
logical_pattern
: disjunctive_pattern
;
disjunctive_pattern
: disjunctive_pattern 'or' conjunctive_pattern
| conjunctive_pattern
;
conjunctive_pattern
: conjunctive_pattern 'and' negated_pattern
| negated_pattern
;
negated_pattern
: 'not' negated_pattern
| primary_pattern
;
not, andet or sont collectivement appelés opérateurs de modèle.
Une negated_pattern correspond si le modèle en cours de négation ne correspond pas, et vice versa. Une conjunctive_pattern nécessite que les deux modèles correspondent. Une disjunctive_pattern nécessite que l’un ou l’autre modèle corresponde. Contrairement à leurs équivalents d’opérateur de langue et && , and et ||orne sont pas des opérateurs de court-circuit.
Il s’agit d’une erreur au moment de la compilation pour qu’une variable de modèle soit déclarée sous un not ou or un opérateur de modèle.
Remarque : Étant donné que ni
oraucunenotaffectation ne peut produire d’affectation définie pour une variable de modèle, il s’agit d’une erreur de déclarer celle-ci dans ces positions. Note de fin
Dans un conjunctive_pattern, le type d’entrée du deuxième modèle est réduit par les exigences de réduction de type du premier modèle du and. Le type restreint d’un modèle P est défini comme suit :
- S’il
Ps’agit d’un modèle de type, le type étroit est le type du modèle de type. - Sinon, s’il s’agit
Pd’un modèle de déclaration, le type restreint est le type du modèle de déclaration. - Sinon, s’il s’agit
Pd’un modèle récursif qui donne un type explicite, le type étroit est ce type. - Sinon, si
Pelle est mise en correspondance via les règles d’unITuplepositional_pattern (§11.2.5), le type étroit est le typeSystem.ITuple. - Sinon, s’il s’agit
Pd’un modèle constant où la constante n’est pas la constante Null et où l’expression n’a pas de conversion d’expression constante vers le type d’entrée, le type restreint est le type de la constante. - Sinon, s’il s’agit
Pd’un modèle relationnel où l’expression constante n’a pas de conversion d’expression constante vers le type d’entrée, le type restreint est le type de la constante. - Sinon, s’il s’agit
Pd’unormodèle, le type étroit est le type commun du type étroit des sous-modèles s’il existe un type commun. À cet effet, l’algorithme de type commun considère uniquement les conversions d’identité, de boxe et de référence implicite, et considère tous les sous-modèles d’une séquence deormodèles (ignorant les modèles entre parenthèses). - Sinon, s’il s’agit
Pd’unandmodèle, le type étroit est le type étroit du motif droit. De plus, le type étroit du modèle gauche est le type d’entrée du modèle droit. - Sinon, le type restreint de
Ptype d’entrée estP« type d’entrée ».
Remarque : Comme indiqué par la grammaire,
nota la priorité surand, qui a la priorité suror. Cela peut être explicitement indiqué ou substitué à l’aide de parenthèses. Note de fin
Lorsqu’un modèle apparaît sur le côté droit du ismodèle, l’étendue du modèle est déterminée par la grammaire ; par conséquent, les opérateurs andde modèle , oret not dans le modèle se lient plus étroitement que les opérateurs logiques &&, ||et ! en dehors du modèle.
Exemple :
Console.WriteLine(Classify(13)); Console.WriteLine(Classify(-100)); Console.WriteLine(Classify(5.7)); static string Classify(double measurement) => measurement switch { < -40.0 => "Too low", >= -40.0 and < 0 => "Low", >= 0 and < 10.0 => "Acceptable", >= 10.0 and < 20.0 => "High", >= 20.0 => "Too high", double.NaN => "Unknown", };La sortie produite est
High Too low Acceptableexemple de fin
Exemple :
Console.WriteLine(GetCalendarSeason(new DateTime(2021, 1, 19))); Console.WriteLine(GetCalendarSeason(new DateTime(2021, 10, 9))); Console.WriteLine(GetCalendarSeason(new DateTime(2021, 5, 11))); static string GetCalendarSeason(DateTime date) => date.Month switch { 3 or 4 or 5 => "spring", 6 or 7 or 8 => "summer", 9 or 10 or 11 => "autumn", 12 or 1 or 2 => "winter", _ => throw new ArgumentOutOfRangeException(nameof(date), $"Date with unexpected month: {date.Month}."), };La sortie produite est
winter autumn springexemple de fin
Exemple :
object msg = "msg"; object obj = 5; bool flag = true; // This is parsed as: (msg is (not int) or string) result = msg is not int or string; Console.WriteLine($"msg (\"msg\"): msg is not int or string: {result}"); // This is parsed as: (obj is (int or string)) && flag bool result = obj is int or string && flag; Console.WriteLine($"obj (5), flag (true): obj is int or string && flag: {result}"); // This is parsed as: (obj is int) || ((obj is string) && flag) result = obj is int || obj is string && flag; Console.WriteLine($"obj (5), flag (true): obj is int || obj is string && flag: {result}"); flag = false; // This is parsed as: (obj is (int or string)) && flag result = obj is int or string && flag; Console.WriteLine($"obj (5), flag (false): obj is int or string && flag: {result}"); // This is parsed as: (obj is int) || ((obj is string) && flag) result = obj is int || obj is string && flag; Console.WriteLine($"obj (5), flag (false): obj is int || obj is string && flag: {result}");La sortie produite est
msg ("msg"): msg is not int or string: True obj (5), flag (true): obj is int or string && flag: True obj (5), flag (true): obj is int || obj is string && flag: True obj (5), flag (false): obj is int or string && flag: False obj (5), flag (false): obj is int || obj is string && flag: Trueexemple de fin
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 l’une des conditions suivantes est en attente :
- la spécification du comportement d’exécution de ce modèle correspond
PKà . -
Pest une type_pattern pour le typeTetKn’est pasnullet le type d’exécution d’estKTou d’un type dérivé ouTd’un type qui implémenteT. -
Pest une relational_pattern avec l’opérateur « op » et la constantev, et l’expressionK« op »vserait évaluée àtrue. -
Pest une negated_patternnot P₁etP₁ne correspondKpas . -
Pest une conjunctive_patternP₁ and P₂et les deuxP₁correspondraientKetP₂correspondraientK. -
Pest une disjunctive_patternP₁ or P₂etP₁correspondraitKouP₂correspondraitK. -
Pest une discard_pattern.
Un ensemble de modèles Qsubsume un modèle P si l’une des conditions suivantes est en attente :
-
Pest un modèle constant et l’un des modèles de l’ensemble correspondraitPà la valeur convertie de l’ensembleQ -
Pest 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 .Qnull -
Pest un modèle de déclaration avec typeTet l’ensemble de modèlesQest exhaustif pour le typeT(§11.4). -
Pest une type_pattern pour le typeTet l’ensemble de modèlesQest exhaustif pour le typeT. -
Pest une relational_pattern avec l’opérateur « op » et la valeurvconstante , et pour chaque valeur du type d’entrée répondant à la relation « op »,vcertains modèles de l’ensembleQcorrespondent à cette valeur. -
Pest un disjunctive_patternP₁ or P₂et l’ensemble de sous-énumérations etQde sous-ensemblesQP₁P₂de modèles . -
Pest une conjunctive_patternP₁ and P₂et au moins l’une des conservations suivantes :Qsous-sommesP₁, ouQsous-sommesP₂. -
Pest une negated_patternnot P₁etQest exhaustive pour le type d’entrée considérant uniquement les valeurs non mises en correspondance parP₁. -
Pest une discard_pattern et l’ensemble de modèlesQest exhaustif pour le type de la valeur d’entrée du modèle, et la valeur d’entrée du modèle n’est pas d’un type nullable ou un modèle dans lequel correspondraitQnull. - Certains modèles dans
Qsont un disjunctive_patternQ₁ or Q₂et le remplacement de ce modèle parQ₁unQensemble qui génère un ensemble qui sous-énuméreP, ou le remplacerQ₂par générerait un ensemble qui sous-énuméreP. - Certains modèles sont
Qun negated_patternnot Q₁etPne correspondent pas à une valeur quiQ₁correspond.
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 :
-
Test un type intégral ou enum, ou une version nullable de l’un de ces éléments, et pour chaque valeur possible duTtype sous-jacent non nullable, un modèle dans lequelQil correspondrait à cette valeur ; ou - Certains modèles sont
Qun modèle var ; ou - Un modèle de
Qdéclaration est 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 àDpartir deT; ou - Certains modèles sont
Qun type_pattern pour le typeD, et il existe une conversion d’identité, une conversion de référence implicite ou une conversion de boxe à partir deT;Dou - Certains modèles sont
Qun discard_pattern ; ou - Les modèles inclus
Qincluent une combinaison de relational_patterns et de constant_patterndont les plages couvrent collectivement toutes les valeurs possibles du type sous-jacent non Nullable.TPourfloatetdoubleles types, cela inclutSystem.Double.NaNouSystem.Single.NaNrespectivement, carNaNn’est mis en correspondance par aucun modèle relationnel ; ou - Certains modèles dans sont
Qun disjunctive_patternP₁ or P₂, et le remplacement de ce modèle par les deuxP₁etP₂dansQun ensemble qui est exhaustif pourT; ou - Certains modèles dans sont
Qun negated_patternnot P₁, et les modèles en même temps que les valeurs non mises enQcorrespondance parP₁toutes les valeurs possibles deT. Une negated_patternnot P₁est exhaustive par elle-même lorsqu’elleP₁ne correspond à aucune valeur possible deT; ou - Certains modèles dans sont
Qun conjunctive_patternP₁ and P₂, et l’ensemble contenant uniquementP₁est exhaustif pourTet l’ensemble contenant uniquementP₂est exhaustif pourT.
Remarque : Lorsqu’un modèle de type inclut des types nullables, le modèle peut être exhaustif pour le type, mais génère toujours un avertissement, car le modèle de type ne correspond pas à une
nullvaleur. Note de fin
Remarque : Pour les types à virgule flottante, la combinaison de modèles
< 0et>= 0n’est pas exhaustive, car aucun modèle relationnel ne correspondNaN. Un ensemble exhaustif correct serait< 0,>= 0etdouble.NaN(oufloat.NaN). Note de fin
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