Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
11.1 Allmänt
Ett mönster är en syntaktisk form som kan användas med operatorn is (§12.14.12), i en switch_statement (§13.8.3) och i en switch_expression (§12.11) för att uttrycka formen på data som inkommande data ska jämföras med. Mönster kan vara rekursiva, så att delar av data kan matchas mot undermönster.
Ett mönster testas mot ett värde i ett antal kontexter:
- I en switch-instruktion testas mönstret för en ärendeetikett mot uttrycket för switch-instruktionen.
- I en is-pattern-operator testas mönstret till höger mot uttrycket till vänster.
- I ett växeluttryck testas mönstret för en switch_expression_arm mot uttrycket på växeluttryckets vänstra sida.
- I kapslade kontexter testas undermönstret mot värden som hämtats från egenskaper, fält eller indexeras från andra indatavärden, beroende på mönsterformuläret.
Värdet som ett mönster testas mot kallas mönsterindatavärdet.
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
| positional_pattern
| property_pattern
| discard_pattern
;
Vissa mönsterkan 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 typenTextReaderkan 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 typenobjectkan 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.
Ordningen för utvärdering av åtgärder och biverkningar under mönstermatchning (anrop till Deconstruct, egenskapsåtkomster och anrop av metoder i System.ITuple) har inte angetts.
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, om du vill ange värdet i en variabel av den typen.
declaration_pattern
: type simple_designation
;
simple_designation
: discard_designation
| single_variable_designation
;
discard_designation
: '_'
;
single_variable_designation
: identifier
;
En simple_designation med token _ ska betraktas som en discard_designation snarare än en single_variable_designation.
Körningstypen för värdet testas mot typen i mönstret med samma regler som anges i operatorn is-type (§12.14.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) eller en nullbar referenstyp (§8.9.3). Det här mönsterformuläret matchar aldrig ett null värde.
Obs! Uttrycket
e is Tis-type och deklarationsmönstrete is T _är likvärdiga närTdet inte är en nullbar typ. slutkommentar
Med tanke på ett mönsterindatavärde (§11.1) e, om simple_designation är discard_designation, anger det ett ignorerande (§9.2.9.2), och värdet på 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 annars är single_variable_designation introduceras en lokal variabel (§9.2.9) av den angivna typen som namnges 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.ET
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
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 idom 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ärtruevid körning och variabelnvinnehåller värdet3av typeninti blocket. Efter blocket är variabelnvi omfånget, men inte definitivt tilldelad. 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
Pvärdet e om resultatet av uttryckete == värtrue, annars - mönstret
Pmatchar värdet e omobject.Equals(e, v)returnerartrue.
Exempel: Instruktionen
switchi 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
| tuple_designation
;
tuple_designation
: '(' designations? ')'
;
designations
: designation (',' designation)*
;
Givet ett mönstrat indatavärde (§11.1) e, om beteckningenär discard_designation, det antecknar en kassera (§9.2.9.2), och värdera av e är inte bundet till något. (Ä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.) Annars, om beteckningenär single_variable_designation, vid körning är värdet e bundet till en nyligen introducerad lokal variabel (§9.2.9) av det namnet vars typ är den statiska typen av e, och 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.
Om beteckning är en tuple_designation, är mönstret likvärdigt med en positional_pattern (§11.2.5) av formbeteckningen(var, ...
) där beteckningenär de som finns inom tuple_designation. Mönstret var (x, (y, z)) motsvarar till (var x, (var y, var z))exempel .
11.2.5 Positionsmönster
En positional_pattern kontrollerar att indatavärdet inte nullär , anropar en lämplig Deconstruct metod (§12.7) och utför ytterligare mönstermatchning på de resulterande värdena. Den stöder också en tupplarliknande mönstersyntax (utan att typen anges) när typen av indatavärde är samma som typen som innehåller Deconstruct, eller om typen av indatavärde är en tupplartyp, eller om typen av indatavärde är object eller System.ITuple och körningstypen för uttrycket implementerar System.ITuple.
positional_pattern
: type? '(' subpatterns? ')' property_subpattern? simple_designation?
;
subpatterns
: subpattern (',' subpattern)*
;
subpattern
: pattern
| identifier ':' pattern
;
Med tanke på en matchning av ett indatavärde med mönstertypens(undermönster), väljs en metod genom att söka i typ efter tillgängliga deklarationer av Deconstruct och välja en av dem med samma regler som för dekonstruktionsdeklarationen.
Det är ett fel om en positional_pattern utelämnar typen, har ett enda undermönster utan identifierare, inte har någon property_subpattern och inte har någon simple_designation. Detta skiljer sig mellan en constant_pattern som är parentesiserad och en positional_pattern.
För att extrahera de värden som ska matchas mot mönstren i listan,
- Om typen utelämnas och indatauttryckets typ är en tuppelns typ, ska antalet undermönster vara detsamma som tuppelns kardinalitet. Varje tuppelns element matchas mot motsvarande underavsnitt och matchningen lyckas om alla dessa lyckas. Om någon underordnad har en identifierare, ska det namnge ett tupppelelement vid motsvarande position i tuppelns typ.
- Om en lämplig
Deconstructfinns som medlem av typen är det annars ett kompileringsfel om typen av indatavärde inte är mönsterkompatibel med typen. Vid körning testas indatavärdet mot typ. Om detta misslyckas misslyckas positionsmönstermatchningen. Om det lyckas konverteras indatavärdet till den här typen ochDeconstructanropas med nya kompilatorgenererade variabler för att ta emot utdataparametrarna. Varje värde som togs emot matchas mot motsvarande undermönster och matchningen lyckas om alla dessa lyckas. Om någon underordnad har en identifierare ska den ge en parameter namnet på motsvarande positionDeconstruct. - Annars, om typen utelämnas och indatavärdet är av typen
objecteller någon typ som kan konverteras tillSystem.ITupleav en implicit referenskonvertering, och ingen identifierare visas bland underavsnitten, använderSystem.ITuplematchningen . - Annars är mönstret ett kompileringsfel.
Ordningen i vilken underavsnitt matchas vid körning är ospecificerad och en misslyckad matchning kanske inte försöker matcha alla undermönster.
Exempel: Här dekonstruerar vi ett uttrycksresultat och matchar de resulterande värdena mot motsvarande kapslade mönster:
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); }slutexempel
Exempel: Namnen på tuppelns element och dekonstruktionsparametrar kan användas i ett positionsmönster enligt följande:
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); }De utdata som genereras är
Sum of [10 20 30] is 60slutexempel
11.2.6 Egenskapsmönster
En property_pattern kontrollerar att indatavärdet inte nullär och matchar rekursivt värden som extraheras med hjälp av tillgängliga egenskaper eller fält.
property_pattern
: type? property_subpattern simple_designation?
;
property_subpattern
: '{' '}'
| '{' subpatterns ','? '}'
;
Det är ett fel om ett underavsnitt av en property_pattern inte innehåller någon identifierare.
Det är ett kompileringsfel om typen är en nullbar värdetyp (§8.3.12) eller en nullbar referenstyp (§8.9.3).
Obs! Ett null-kontrollmönster faller ur ett trivialt egenskapsmönster. För att kontrollera om strängen
sinte är null kan man skriva något av följande formulär:#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 {}) ...slutkommentar Med tanke på en matchning av ett uttryck e till mönstertypen
{property_pattern_list}är det ett kompileringsfel om uttrycket e inte är mönsterkompatibelt med typen T som anges efter typ. Om typen saknas antas typen vara den statiska typen e. Var och en av de identifierare som förekommer till vänster i dess property_pattern_list skall ange en tillgänglig läsbar egenskap eller ett fält i T. Om simple_designation för property_pattern finns deklarerar den en mönstervariabel av typen T.
Vid körning testas uttrycket mot T. Om detta misslyckas misslyckas egenskapsmönstermatchningen och resultatet blir false. Om det lyckas läss varje property_subpattern fält eller egenskap och dess värde matchas mot motsvarande mönster. Resultatet av hela matchningen är false bara om resultatet av något av dessa är false. Ordningen där undermönster matchas anges inte och en misslyckad matchning kanske inte testar alla undermönster vid körning. Om matchningen lyckas och simple_designation för property_pattern är en single_variable_designation tilldelas den deklarerade variabeln det matchade värdet.
Property_pattern kan användas för att mönstermatcha med anonyma typer.
Exempel:
var o = ...; if (o is string { Length: 5 } s) ...slutexempel
Exempel: En körningstypkontroll och en variabeldeklaration kan läggas till i ett egenskapsmönster enligt följande:
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."), };De utdata som genereras är
Hello Hi! 12345 abcslutexempel
11.2.7 Ignorera mönster
Varje uttryck matchar mönstret ignorera, vilket resulterar i värdet för uttrycket som ignoreras.
discard_pattern
: '_'
;
Det är ett kompileringsfel att använda ett ignorerande mönster i en relational_expression av formuläret relational_expressionismönster eller som mönstret för en switch_label.
Obs! Om du vill matcha alla uttryck använder du en var_pattern med ignorera
var _. slutkommentar
Exempel:
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, };De utdata som genereras är
5.0 0.0 0.0Här används ett ignorerande mönster för att hantera
nulloch alla heltalsvärden som inte har motsvarande medlem iDayOfWeekuppräkningen. Det garanterar att uttrycketswitchhanterar alla möjliga indatavärden. slutexempel
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 Pskulle matcha en konstant K om specifikationen för det mönstrets körningsbeteende är som P matchar K.
En uppsättning mönster Qundersummar 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ättningenQskulle matchaPdet 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 .Qnull -
Pär ett deklarationsmönster med typToch 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 avTden underliggande typen som inte kan nollföras skulle något mönster iQmatcha 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ånTtillD.
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