11 Patronen en patroonkoppeling
11.1 Algemeen
Een patroon is een syntactische vorm die kan worden gebruikt met de is
operator (§12.12.12) en in een switch_statement (§13.8.3) om de vorm van gegevens uit te drukken waarmee binnenkomende gegevens moeten worden vergeleken. Een patroon wordt getest op basis van de expressie van een switchinstructie of tegen een relational_expression die zich aan de linkerkant van een operator bevindt, die elk eenis
wordt genoemd.
11.2 Patroonformulieren
11.2.1 Algemeen
Een patroon kan een van de volgende vormen hebben:
pattern
: declaration_pattern
| constant_pattern
| var_pattern
;
Een declaration_pattern en een var_pattern kunnen leiden tot de declaratie van een lokale variabele.
Elk patroonformulier definieert de set typen voor invoerwaarden waarop het patroon kan worden toegepast. Een patroon P
is van toepassing op een type T
als T
het een van de typen is waarvan de waarden overeenkomen met het patroon. Het is een compilatiefout als een patroon P
wordt weergegeven in een programma dat overeenkomt met een patrooninvoerwaarde (§11.1) van het type T
als P
dit niet van toepassing is op T
.
Voorbeeld: In het volgende voorbeeld wordt een compilatiefout gegenereerd omdat het type
v
compileertijd isTextReader
. Een variabele van het typeTextReader
kan nooit een waarde hebben die compatibel is metstring
:TextReader v = Console.In; // compile-time type of 'v' is 'TextReader' if (v is string) // compile-time error { // code assuming v is a string }
Het volgende genereert echter geen compilatietijdfout omdat het type
v
compileertijd isobject
. Een variabele van het typeobject
kan een waarde hebben die compatibel is metstring
:object v = Console.In; if (v is string s) { // code assuming v is a string }
eindvoorbeeld
Elk patroonformulier definieert de set waarden waarvoor het patroon overeenkomt met de waarde tijdens runtime.
11.2.2 Declaratiepatroon
Een declaration_pattern wordt gebruikt om te testen of een waarde een bepaald type heeft en, als de test slaagt, de waarde in een variabele van dat type opgeeft.
declaration_pattern
: type simple_designation
;
simple_designation
: single_variable_designation
;
single_variable_designation
: identifier
;
Het runtimetype van de waarde wordt getest op basis van het type in het patroon met dezelfde regels die zijn opgegeven in de operator is-type (§12.12.12.12.1). Als de test slaagt, komt het patroon overeen met die waarde. Het is een compilatietijdfout als het type een type null-waarde is (§8.3.12). Dit patroonformulier komt nooit overeen met een null
waarde.
Opmerking: De is-type-expressie
e is T
en het declaratiepatroone is T _
zijn equivalent wanneerT
het geen null-type is. eindnotitie
Uitgaande van een patrooninvoerwaarde (§11.1) e, als de simple_designation de -id_
is, wordt een verwijdering (§9.2.9.2) aangeduid en is de waarde van e niet gebonden aan iets. (Hoewel een gedeclareerde variabele met de naam _
op dat moment mogelijk binnen het bereik valt, is deze benoemde variabele niet zichtbaar in deze context.) Als simple_designation een andere identificator is, wordt een lokale variabele (§9.2.9.1) van het opgegeven type met de opgegeven identificator geïntroduceerd. Aan die lokale variabele wordt de waarde van de invoerwaarde van het patroon toegewezen wanneer het patroon overeenkomt met de waarde.
Bepaalde combinaties van het statische type van de patrooninvoerwaarde en het opgegeven type worden beschouwd als niet compatibel en resulteren in een compilatiefout. Een waarde van het statische type E
wordt geacht een patroon te zijn dat compatibel is met het type T
als er een identiteitsconversie bestaat, een impliciete of expliciete verwijzingsconversie, een boksconversie of een conversie van boksen opheffen vanE
, T
of als E
het een T
open type is (§8.4.3). Een declaratiepatroon met de naam van een type T
is van toepassing op elk type E
waarvoor E
een patroon compatibel is met T
.
Opmerking: de ondersteuning voor open typen kan het handigst zijn bij het controleren van typen die struct- of klassetypen kunnen zijn, en boksen moet worden vermeden. eindnotitie
Voorbeeld: Het declaratiepatroon is handig voor het uitvoeren van runtime-typetests van referentietypen en vervangt het idioom
var v = expr as Type; if (v != null) { /* code using v */ }
met de iets beknopter
if (expr is Type v) { /* code using v */ }
eindvoorbeeld
Dit is een fout als het type een type null-waarde is.
Voorbeeld: Het declaratiepatroon kan worden gebruikt om waarden van null-typen te testen: een waarde van het type
Nullable<T>
(of een vakkenT
) komt overeen met een typepatroonT2 id
als de waarde niet null is enT2
ofT
een basistype of interface vanT
. Bijvoorbeeld in het codefragmentint? x = 3; if (x is int v) { /* code using v */ }
De voorwaarde van de
if
instructie istrue
tijdens runtime en de variabelev
bevat de waarde3
van het typeint
in het blok. eindvoorbeeld
11.2.3 Constant patroon
Een constant_pattern wordt gebruikt om de waarde van een patrooninvoerwaarde (§11.1) te testen op basis van de opgegeven constante waarde.
constant_pattern
: constant_expression
;
Een constant patroon P
is van toepassing op een type T
als er een impliciete conversie van de constante expressie van P
het type T
is.
Voor een constant patroon P
is de geconverteerde waarde
- als het type van de patrooninvoerwaarde een integraal type of een opsommingstype is, wordt de constante waarde van het patroon geconverteerd naar dat type; anders
- als het type van de invoerwaarde van het patroon de null-versie van een integraal type of een enumtype is, wordt de constante waarde van het patroon geconverteerd naar het onderliggende type; anders
- de waarde van de constante waarde van het patroon.
Gegeven een patrooninvoerwaarde e en een constant patroon P
met geconverteerde waarde v,
- als e een integraal type of opsommingstype of een null-vorm van een van deze heeft en v een integraal type heeft, komt het patroon
P
overeen met de waarde e als het resultaat van de expressiee == v
istrue
; anders - het patroon
P
overeenkomt met de waarde e alsobject.Equals(e, v)
deze retourneerttrue
.
Voorbeeld: De
switch
instructie in de volgende methode maakt gebruik van vijf constante patronen in de caselabels.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(...); } }
eindvoorbeeld
11.2.4 Var pattern
Een var_patternkomt overeen met elke waarde. Dat wil gezegd, een patroonkoppelingsbewerking met een var_pattern altijd slaagt.
Een var_pattern is van toepassing op elk type.
var_pattern
: 'var' designation
;
designation
: simple_designation
;
Uitgaande van een patrooninvoerwaarde (§11.1) e, als aanduiding de -id_
is, wordt een verwijdering aangegeven (§9.2.9.2) en de waarde van e is niet gebonden aan iets. (Hoewel op dat moment een gedeclareerde variabele met die naam mogelijk binnen het bereik valt, wordt die benoemde variabele niet gezien in deze context.) Als aanduiding een andere id is, is tijdens runtime de waarde van e gebonden aan een nieuw geïntroduceerde lokale variabele (§9.2.9.1) van die naam waarvan het type het statische type eis en de patrooninvoerwaarde wordt toegewezen aan die lokale variabele.
Dit is een fout als de naam var
zou binden aan een type waarbij een var_pattern wordt gebruikt.
11.3 Patroonsubsumption
In een switch-instructie is het een fout als het patroon van een case wordt aangevuld met de voorgaande reeks niet-bewaakte zaken (§13.8.3). Informeel betekent dit dat elke invoerwaarde zou overeenkomen met een van de vorige gevallen. De volgende regels definiëren wanneer een set patronen een bepaald patroon samenvat:
Een patroon P
komt overeen met een constante K
als de specificatie voor het runtimegedrag van dat P
patroon overeenkomt K
.
Een set patronen Q
bevat een patroon P
als een van de volgende voorwaarden geldt:
-
P
is een constant patroon en een van de patronen in de setQ
komt overeen metP
de geconverteerde waarde -
P
is een var-patroon en de set patronenQ
is volledig (§11.4) voor het type van de patrooninvoerwaarde (§11.1), en de patrooninvoerwaarde is niet van een null-type of een bepaald patroon komtQ
overeennull
. -
P
is een declaratiepatroon met typeT
en de set patronenQ
is volledig voor het typeT
(§11.4).
11.4 Patroon volledigheid
Informeel is een set patronen volledig voor een type als, voor elke mogelijke waarde van dat type anders dan null, een bepaald patroon in de set van toepassing is. De volgende regels definiëren wanneer een set patronen volledig is voor een type:
Een reeks patronen Q
is volledig voor een type T
als een van de volgende voorwaarden geldt:
-
T
is een integraal of opsommingstype, of een null-versie van een van deze, en voor elke mogelijke waarde vanT
het niet-nulle onderliggende type komt een bepaald patroonQ
overeen met die waarde; of - Een bepaald patroon is
Q
een var-patroon; of - Een patroon in
Q
is een declaratiepatroon voor het typeD
en er is een identiteitsconversie, een impliciete verwijzingsconversie of een boksconversie vanT
naarD
.
Voorbeeld:
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; } }
eindvoorbeeld
ECMA C# draft specification