11 Mönster och mönstermatchning
11.1 Allmänt
Ett mönster är en syntaktisk form som kan användas med operatorn is
(§12.12.12) och i en switch_statement (§13.8.3) för att uttrycka formen på data som inkommande data ska jämföras med. Ett mönster testas mot uttrycket för en switch-instruktion, eller mot en relational_expression som finns till vänster om en operator, som var och en kallas för ettis
.
11.2 Mönsterformulär
11.2.1 Allmänt
Ett mönster kan ha något av följande formulär:
pattern
: declaration_pattern
| constant_pattern
| var_pattern
;
En declaration_pattern och en var_pattern kan resultera i deklarationen av en lokal variabel.
Varje mönsterformulär definierar uppsättningen med typer för indatavärden som mönstret kan tillämpas på. Ett mönster P
gäller för en typ T
om T
är bland de typer vars värden mönstret kan matcha. Det är ett kompileringsfel om ett mönster P
visas i ett program för att matcha ett mönsterindatavärde (§11.1) av typen T
om P
det inte är tillämpligt på T
.
Exempel: I följande exempel genereras ett kompileringsfel eftersom kompileringstidstypen
v
ärTextReader
. En variabel av typenTextReader
kan aldrig ha ett värde som är referenskompatibelt medstring
:TextReader v = Console.In; // compile-time type of 'v' is 'TextReader' if (v is string) // compile-time error { // code assuming v is a string }
Följande genererar dock inget kompileringsfel eftersom kompileringstidstypen
v
ärobject
. En variabel av typenobject
kan ha ett värde som är referenskompatibelt medstring
:object v = Console.In; if (v is string s) { // code assuming v is a string }
slutexempel
Varje mönsterformulär definierar den uppsättning värden som mönstret matchar värdet för vid körning.
11.2.2 Deklarationsmönster
En declaration_pattern används för att testa att ett värde har en viss typ och, om testet lyckas, ange värdet i en variabel av den typen.
declaration_pattern
: type simple_designation
;
simple_designation
: single_variable_designation
;
single_variable_designation
: identifier
;
Körningstypen för värdet testas mot typen i mönstret med samma regler som anges i operatorn is-type (§12.12.12.12.1). Om testet lyckas matchar mönstret det värdet. Det är ett kompileringsfel om typen är en nullbar värdetyp (§8.3.12). Det här mönsterformuläret matchar aldrig ett null
värde.
Obs! Uttrycket
e is T
is-type och deklarationsmönstrete is T _
är likvärdiga närT
det inte är en nullbar typ. slutkommentar
Med tanke på ett mönsterinmatningsvärde (§11.1) e, om simple_designation är identifierare_
, anges ett ignorerande (§9.2.9.2) och värdet för e är inte bundet till någonting. (Även om en deklarerad variabel med namnet _
kan finnas i omfånget vid den tidpunkten visas inte den namngivna variabeln i den här kontexten.) Om simple_designation är någon annan identifierare introduceras en lokal variabel (§9.2.9.1) av den angivna typen med namnet av den angivna identifieraren. Den lokala variabeln tilldelas värdet för mönsterindatavärdet när mönstret matchar värdet.
Vissa kombinationer av statisk typ av mönsterindatavärdet och den angivna typen anses vara inkompatibla och resulterar i ett kompileringsfel. Ett värde av statisk typ E
sägs vara mönsterkompatibelt med typen T
om det finns en identitetskonvertering, en implicit eller explicit referenskonvertering, en boxningskonvertering eller en avboxningskonvertering från E
till T
, eller om någon E
av dem eller T
är en öppen typ (§8.4.3). Ett deklarationsmönster som namnger en typ gäller för varje typ T
som är mönsterkompatibel med E
.E
T
Obs! Stödet för öppna typer kan vara mest användbart när du kontrollerar typer som kan vara antingen struct- eller klasstyper, och boxning bör undvikas. slutkommentar
Exempel: Deklarationsmönstret är användbart för att utföra körningstyptester av referenstyper och ersätter formspråket
var v = expr as Type; if (v != null) { /* code using v */ }
med den något mer koncisa
if (expr is Type v) { /* code using v */ }
slutexempel
Det är ett fel om typen är en nullbar värdetyp.
Exempel: Deklarationsmönstret kan användas för att testa värden för null-typer: ett värde av typen
Nullable<T>
(eller en rutadT
) matchar ett typmönsterT2 id
om värdet inte är null ochT2
ärT
, eller någon bastyp eller gränssnitt förT
. Till exempel i kodfragmentetint? x = 3; if (x is int v) { /* code using v */ }
Villkoret för -instruktionen
if
ärtrue
vid körning och variabelnv
innehåller värdet3
av typenint
i blocket. slutexempel
11.2.3 Konstant mönster
En constant_pattern används för att testa värdet för ett mönsterindatavärde (§11.1) mot det angivna konstantvärdet.
constant_pattern
: constant_expression
;
Ett konstant mönster P
gäller för en typ T
om det finns en implicit konvertering från det konstanta uttrycket för P
till typen T
.
För ett konstant mönster P
är dess konverterade värde
- Om mönstrets indatavärdestyp är en integraltyp eller en uppräkningstyp konverteras mönstrets konstantvärde till den typen. annars
- Om mönstrets indatavärdestyp är den nullbara versionen av en integraltyp eller en uppräkningstyp konverteras mönstrets konstantvärde till dess underliggande typ. annars
- värdet för mönstrets konstanta värde.
Givet ett mönsterindatavärde e och ett konstant mönster P
med konverterat värde v,
- om e har en integraltyp eller uppräkningstyp, eller en nullbar form av en av dessa, och v har en integrerad typ, matchar mönstret
P
värdet e om resultatet av uttryckete == v
ärtrue
, annars - mönstret
P
matchar värdet e omobject.Equals(e, v)
returnerartrue
.
Exempel: Instruktionen
switch
i följande metod använder fem konstanta mönster i sina skiftlägesetiketter.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(...); } }
slutexempel
11.2.4 Var-mönster
Ett var_patternmatchar varje värde. En mönstermatchningsåtgärd med en var_pattern lyckas alltså alltid.
En var_pattern gäller för varje typ.
var_pattern
: 'var' designation
;
designation
: simple_designation
;
Med tanke på ett mönsterinmatningsvärde (§11.1) e, om beteckning är identifierare_
, anger det en bortkastning (§9.2.9.2), och värdet för e är inte bundet till någonting. (Även om en deklarerad variabel med det namnet kan finnas i omfånget vid den tidpunkten visas inte den namngivna variabeln i den här kontexten.) Om beteckning är någon annan identifierare, är värdet för e bundet till en nyligen introducerad lokal variabel (§9.2.9.1) av det namnet vars typ är den statiska typen av eoch mönstrets indatavärde tilldelas till den lokala variabeln.
Det är ett fel om namnet var
skulle binda till en typ där en var_pattern används.
11.3 Undersummor för mönster
I en switch-instruktion är det ett fel om ett ärendes mönster undersummas av föregående uppsättning obevakade ärenden (§13.8.3). Informellt innebär detta att alla indatavärden skulle ha matchats av ett av de tidigare fallen. Följande regler definierar när en uppsättning mönster undersummar ett givet mönster:
Ett mönster P
skulle matcha en konstant K
om specifikationen för det mönstrets körningsbeteende är som P
matchar K
.
En uppsättning mönster Q
undersummar ett mönster P
om något av följande villkor gäller:
-
P
är ett konstant mönster och något av mönstren i uppsättningenQ
skulle matchaP
det konverterade värdet -
P
är ett var-mönster och uppsättningen mönster är fullständig (§11.4) för typen av mönsterindatavärde (Q
), och antingen är mönsterindatavärdet inte av en nullbar typ eller så matchar något mönster i .Q
null
-
P
är ett deklarationsmönster med typT
och uppsättningen mönsterQ
är fullständig för typenT
(§11.4).
11.4 Mönster fullständighet
Informellt är en uppsättning mönster uttömmande för en typ om, för varje möjligt värde av den typen förutom null, något mönster i uppsättningen är tillämpligt. Följande regler definierar när en uppsättning mönster är uttömmande för en typ:
En uppsättning mönster Q
är fullständig för en typ T
om något av följande villkor gäller:
-
T
är en integrerad eller uppräkningstyp, eller en nullbar version av en av dessa, och för varje möjligt värde avT
den underliggande typen som inte kan nollföras skulle något mönster iQ
matcha det värdet, eller - Vissa mönster i
Q
är ett var-mönster, eller - Vissa mönster i
Q
är ett deklarationsmönster för typenD
, och det finns en identitetskonvertering, en implicit referenskonvertering eller en boxningskonvertering frånT
tillD
.
Exempel:
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; } }
slutexempel
ECMA C# draft specification