Kommentar
Å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 kan användas med operatorn is (§12.15.12), i en switch_statement (§13.8.3) och i en switch_expression (§12.12) för att beskriva formen på data som inkommande data ska jämföras med. Mönster kan kapslas, där delar av data matchas mot undermönster.
Ett mönster testas mot ett värde i ett antal kontexter:
- I en switch_statement testas mönstret för en switch_label mot selector_expression för switch_statement.
- Med en is-pattern-operator testas mönstret till höger mot uttrycket till vänster.
- I en switch_expression testas mönstret för en switch_expression_arm mot uttrycket på switch_expression vänstra sidan.
- 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
: logical_pattern
;
primary_pattern
: parenthesized_pattern
| declaration_pattern
| constant_pattern
| var_pattern
| positional_pattern
| property_pattern
| discard_pattern
| type_pattern
| relational_pattern
| logical_pattern
| list_pattern
| slice_pattern
;
Produktionen '(' pattern ')' gör att ett mönster kan omges av parenteser för att framtvinga utvärderingsordningen mellan mönster som kombineras med någon av de logical_patterns.
Om indata kan erkännas syntaktiskt som både en constant_pattern och en positional_pattern ska constant_pattern väljas.
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 inte ett 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 medlemmar System.Runtime.CompilerServices.ITuplei ) 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
;
Vid erkännande av en simple_designation om både discard_designation och single_variable_designation alternativ är tillämpliga, ska den förra väljas.
Obs! ANTLR gör det angivna valet automatiskt på grund av ordningen på alternativen för simple_designation. slutkommentar
Körningstypen för värdet testas mot typen i mönstret med samma regler som anges i operatorn is-type (§12.15.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
Givet ett mönsterinmatningsvärde (§11.1) e, om simple_designation är en discard_designation, som anger ett utkast (§9.2.9.2), är värdet för e inte bundet till någonting. Om simple_designation annars är en 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.
Obs! Denna behandling av
_inom en declaration_pattern skiljer sig från en fristående_skriven som ett mönster (§11.2.7): i det senare fallet är en konstant i omfånget eller typen med namnet_, om någon, inte dold. slutkommentar
En typ E sägs vara mönsterkompatibel med typen T om det finns en identitetskonvertering, en implicit eller explicit referenskonvertering, en boxningskonvertering, en konvertering av oboxning eller en implicit eller explicit nullbar värdetypskonvertering från E till T, eller om antingen E eller T är en öppen typ (§8.4.3). Ett deklarationsmönster som namnger en typ Tgäller för (§11.2.1) varje typ E som E är mönsterkompatibel med T. Det är ett kompileringsfel om ett deklarationsmönster som namnger en typ T används för att matcha ett mönsterindatavärde (§11.1) vars statiska typ E inte är mönsterkompatibel med 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
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 - om e är av typen
System.Span<char>ellerSystem.ReadOnlySpan<char>, och v är en konstant sträng, och v inte har ett konstant värde pånull, anses mönstret matcha omSystem.MemoryExtensions.SequenceEqual<char>(e, System.MemoryExtensions.AsSpan(v))returnerartrue, 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 (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 , extraherar en sekvens med värden från den och matchar varje extraherat värde mot motsvarande undermönster. Värdena extraheras på något av tre sätt: genom att behandla indata som en tuppeln, genom att anropa en Deconstruct metod eller genom att indexera indata via System.Runtime.CompilerServices.ITuple.
Obs! Användningen av
Deconstructhär skiljer sig från den dekonstruktionstransformering på källnivå som definieras i §12.7. slutkommentar
positional_pattern
: type? '(' subpatterns? ')' property_subpattern? simple_designation?
;
subpatterns
: subpattern (',' subpattern)*
;
subpattern
: pattern
| subpattern_name ':' pattern
;
subpattern_name
: identifier
| subpattern_name '.' identifier
;
Låt n vara antalet subpatternsom visas mellan parenteserna. Matchningsstrategin väljs vid kompileringstillfället genom att följande fall tillämpas i ordning. det första fallet vars villkor är uppfyllda används, och de återstående fallen beaktas inte. När ett ärende har valts bekräftas den strategin: eventuella kompileringsfel som anges i det fallet rapporteras och matchning sker inte i ett senare fall.
- Tuppelns form. Om typen utelämnas och den statiska typen av indatavärde är en tupplartyp (§8.3.11) eller om indatavärdet är en tuppelnliteral (§12.8.6), gäller detta fall. Det är ett kompileringsfel om n inte är lika med den tuppelns aritet. Vid körning matchas varje tuppelns element mot motsvarande undermönster. matchningen lyckas om alla dessa lyckas. Om någon underordnad har en identifierare ska den identifieraren namnge tuppelns element vid motsvarande position i tuppelns typ.
- Dekonstruera formulär. Annars, om någon av typerna finns, eller om typen utelämnas och den statiska typen av indatavärde innehåller en tillgänglig
Deconstructmetod (§12.7), gäller det här fallet. Låt D vara typ om typen finns. annars ska D vara den statiska typen av indatavärde. EnDeconstructmetod väljs från D med samma regler för överbelastningsmatchning som för en dekonstruktionsdeklaration, med det ytterligare kravet att dess antaloutparametrar är lika med n. Det är ett kompileringsfel om det inte finns någon sådan metod. Om typen finns är det ett kompileringsfel om den statiska typen av indatavärde inte är mönsterkompatibel (§11.2.2) med typen; vid körning testas indatavärdet mot typen och om testet misslyckas misslyckas positionsmönstermatchningen. Annars konverteras indatavärdet till D och den valdaDeconstructmetoden anropas med nya variabler som tar emot dessoutparametrar. Varje mottaget värde matchas mot motsvarande undermönster och matchningen lyckas om alla dessa lyckas. Om någon underordnad har en identifierare ska den identifieraren namnge parametern på motsvarande positionDeconstructsom . - ITuple-formulär. Annars, om typen utelämnas, inget undermönster har en identifierare och den statiska typen av indatavärde är
object,System.Runtime.CompilerServices.ITupleeller en typ som har en implicit referenskonvertering tillSystem.Runtime.CompilerServices.ITuple, så gäller det här fallet. Vid körningen testas indatavärdet för att vara en icke-instansnullavSystem.Runtime.CompilerServices.ITuple. Om testet misslyckas misslyckas positionsmönstermatchningen. Annars är värdetsLengthegenskap läst och om den inte är lika med n misslyckas positionsmönstermatchningen. För varje i från 1 till n matchas annars värdet som erhålls genom indexering av indatavärdet med i − 1 mot i-th-undermönstret, och matchningen lyckas om alla dessa lyckas. - Annars gäller inget fall och positional_pattern är 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 någon undersändning av en property_pattern inte innehåller någon subpattern_name.
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
}
{ Om uttrycket e inte är mönsterkompatibelt (§11.2.2) är det ett kompileringsfel om uttrycket e inte är mönsterkompatibelt (§11.2.2) med typen T som anges efter typ. Om typen saknas antas typen vara den statiska typen e. Varje subpattern_name som förekommer på vänster sida av dess underordnad ska 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.
En subpattern_name kan referera till en kapslad medlem. I sådana fall är mottagaren för varje namnsökning typen av föregående medlem T₀, med början från indatatypen för property_pattern. Om T är en nullbar typ är T₀ dess underliggande typ, annars är T₀ lika med T. Ett mönster i formuläret { Prop1.Prop2: pattern } motsvarar till { Prop1: { Prop2: pattern } }exempel exakt .
Obs! Detta inkluderar null-kontrollen när T är en nullbar värdetyp eller en referenstyp. Den här null-kontrollen innebär att de kapslade egenskaper som är tillgängliga är egenskaperna för T₀, inte för T. Eftersom upprepade medlemssökvägar tillåts kan kompilering av mönstermatchning dra nytta av vanliga delar av mönster. slutkommentar
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
: '_'
;
Om den syntaktiska kontexten tillåter ett mönster, om token _ skulle matchas som en simple_name (§12.8.4) till en tillgänglig konstant eller till en typ, behandlas den _inte som en discard_pattern. Istället:
- Om
_matchar en tillgänglig konstant tolkas den_som en constant_pattern (§11.2.3) vars konstanta uttryck är den konstanten. - Om
_matchar en typ tolkas konstruktionen relational_expressionis _på höger sida av enisoperator som is-type-operatorn (§12.15.12.1) mot den typen. I andra syntaktiska sammanhang som medger ett mönster är en tom_matchning till en typ inte i sig ett giltigt mönster. Det kan dock_visas som typen av en declaration_pattern (t.ex._ x) eller i andra mönsterformer som uttryckligen namnger en typ.
Den här regeln bevarar bakåtkompatibilitet med kod som definierats _ som en typ eller identifierare innan mönstret ignoreras. Om _ matchar något annat än en tillgänglig konstant eller typ (till exempel en lokal variabel, parameter, fält eller metod) gäller inte regeln och _ förblir en discard_pattern.
Obs! Detta är detsamma som regeln för
vari §11.2.4, förutom att för en konstant eller typ inom omfånget kan_tolkas som en referens till den deklarationen i stället för_att orsaka ett fel. slutkommentar
Om token _ fortfarande är en discard_pattern efter att ha tillämpat föregående regel är det ett kompileringsfel för att discard_pattern visas som hela mönstret för en relational_expression av formuläret relational_expressionismönster, eller som hela mönstret för en switch_label. En discard_pattern kan dock visas som ett underordnat av ett omslutande mönster (till exempel som ett underavsnitt av en positional_pattern eller property_pattern).
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
Exempel: Följande illustrerar hur en konstant i omfånget med namnet
_ändrar tolkningen av en_arm i ettswitchuttryck. IWithoutUnderscoreär armen en discard_pattern och matchar alla_värden. IWithUnderscoregör konstanten_i omfånget_att armen tolkas som en constant_pattern som endast matchar värdet0.static string WithoutUnderscore(int n) => n switch { 1 => "one", _ => "other", }; static string WithUnderscore(int n) { const int _ = 0; return n switch { 1 => "one", _ => "zero", var x => "other: " + x, }; }slutexempel
11.2.8 Typmönster
En type_pattern används för att testa att indatavärdet för mönster (§11.1) har en viss typ.
type_pattern
: type
;
Ett typmönster som namnger en typ Tgäller för varje typ E som E är mönsterkompatibel med T (§11.2.2).
Körningstypen för värdet testas mot typen med samma regler som anges i is-type-operatorn (§12.15.12.1). Om testet lyckas matchar mönstret det värdet. Det är ett kompileringsfel om typen är en nullbar typ. Det här mönsterformuläret matchar aldrig ett null värde.
11.2.9 Relationsmönster
En relational_pattern används för att relationstesta mönsterindatavärdet (§11.1) mot ett konstant värde.
relational_pattern
: '<' relational_expression
| '<=' relational_expression
| '>' relational_expression
| '>=' relational_expression
;
Relational_expression i en relational_pattern krävs för att utvärdera till ett konstant värde.
Relationsmönster stöder relationsoperatorerna , , och på alla inbyggda typer som stöder sådana binära relationsoperatorer med samma typ: <, <=, >, >=, sbyte, byte, shortushortintuintlongulong, char, floatoch uppräkningar.doubledecimalnintnuint
Det är ett kompileringsfel om constant_expressionär double.NaN, float.NaNeller null_literal.
När indatavärdet har en typ för vilken en lämplig inbyggd binär relationsoperator definieras, tas utvärderingen av operatorn som innebörden av relationsmönstret. Annars konverteras indatavärdet till typen av constant_expression med hjälp av en explicit nullbar eller avboxningskonvertering. Det är ett kompileringsfel om det inte finns någon sådan konvertering. Det är ett kompileringsfel om indatatypen är en typparameter som är begränsad till, eller en typ som ärver, från System.Numerics.INumberBase<T> och indatatypen inte har någon lämplig inbyggd binär relationsoperator definierad. Mönstret anses inte matcha om konverteringen misslyckas. Om konverteringen lyckas är resultatet av mönstermatchningsåtgärden resultatet av utvärderingen av uttrycket e «op» v där e är de konverterade indata, «op» är relationsoperatorn och v är constant_expression.
Exempel:
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", };De utdata som genereras är
Too high Unknown Acceptableslutexempel
11.2.10 Logiskt mönster
En logical_pattern används för att negera resultatet av en mönstermatchning, eller för att kombinera resultatet av flera mönstermatchningar med hjälp av konjunktion (and) eller disjunction (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, andoch or kallas tillsammans för mönsteroperatorer.
Ett negated_pattern matchar om mönstret som negeras inte matchar, och vice versa. En conjunctive_pattern kräver att båda mönstren matchar. Ett disjunctive_pattern kräver endera mönstret för att matcha. Till skillnad från deras språkoperatormotsvarigheter och &&||, and och or är inte kortslutningsoperatorer.
Det är ett kompileringsfel för en mönstervariabel som ska deklareras under en not operator eller or mönsteroperator.
Obs! Eftersom varken
notellerorkan generera en bestämd tilldelning för en mönstervariabel är det ett fel att deklarera en i dessa positioner. slutkommentar
I en conjunctive_pattern begränsas indatatypen för det andra mönstret av typen som begränsar kraven för det första mönstret i and. Den begränsade typen av ett mönster P definieras på följande sätt:
- Om
Pär ett typmönster är den begränsade typen typen av typmönstertyp. - Annars, om
Pär ett deklarationsmönster , är den smala typen typen av deklarationsmönstrets typ. - Annars, om
Pär ett rekursivt mönster som ger en explicit typ, är den smala typen den typen. - Annars, om
Pmatchas via reglerna förITuplei en positional_pattern (§11.2.5), är den smala typen typenSystem.ITuple. - Annars, om
Pär ett konstant mönster där konstanten inte är null-konstanten och uttrycket inte har någon konstant uttryckskonvertering till indatatypen, är den begränsade typen typen av konstant. - Om
Pär ett relationsmönster där konstantuttrycket inte har någon konstant uttryckskonvertering till indatatypen är den begränsade typen typen av konstant. - Annars, om
Pär ettormönster, är den smala typen den vanliga typen av den smala typen av undermönster om det finns en sådan gemensam typ. För detta ändamål tar den gemensamma typalgoritmen endast hänsyn till identitets-, boxnings- och implicita referenskonverteringar, och den tar hänsyn till alla undermönster i en sekvens avormönster (ignorerar parenteserade mönster). - Annars, om
Pär ettandmönster, är den smala typen den smala typen av rätt mönster. Dessutom är den begränsade typen av det vänstra mönstret indatatypen för det högra mönstret. - Annars är
Pden begränsade typen avPindatatyp.
Obs! Som indikeras av grammatiken
nothar företräde framförand, som har företräde framföror. Detta kan uttryckligen anges eller åsidosättas med parenteser. slutkommentar
När ett mönster visas på höger sida av isbestäms mönstrets omfattning av grammatiken, vilket innebär att mönsteroperatorerna and, oroch not inom mönstret binder hårdare än de logiska operatorerna &&, ||och ! utanför mönstret.
Exempel:
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", };De utdata som genereras är
High Too low Acceptableslutexempel
Exempel:
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}."), };De utdata som genereras är
winter autumn springslutexempel
Exempel:
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}");De utdata som genereras är
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: Trueslutexempel
11.2.11 Listmönster
En list_pattern matchar en sekvens med element i en lista eller en matris.
list_pattern
: list_pattern_clause simple_designation?
;
list_pattern_clause
: '[' (pattern (',' pattern)* ','?)? ']'
;
En list_pattern är kompatibel med alla typer som kan räknas (§18.1) samt indexerbara (§18.1)– den har en tillgänglig indexerare som tar ett Index argument eller en tillgänglig indexerare med en enda int parameter. Om båda indexerarna finns är det förstnämnda att föredra. (Se §18.4.2 för information om implicit indexstöd.)
Ett mönster i formuläret expr is [1, 2, 3] motsvarar följande kod:
expr.Length is 3
&& expr[new Index(0, fromEnd: false)] is 1
&& expr[new Index(1, fromEnd: false)] is 2
&& expr[new Index(2, fromEnd: false)] is 3
Exempel:
int[] numbers = { 1, 2, 3 }; Console.WriteLine(numbers is [1, 2, 3]); // True Console.WriteLine(numbers is [1, 2, 4]); // False Console.WriteLine(numbers is [1, 2, 3, 4]); // False Console.WriteLine(numbers is [0 or 1, <= 2, >= 3 and not 7]); // Trueslutexempel
Mönstret ignorera (§11.2.7) matchar ett enskilt element.
Exempel:
List<int> numbers = new() { 1, 2, 3 }; if (numbers is [_, var second, _]) { Console.WriteLine($"The second element is {second}."); }slutexempel
11.2.12 Segmentmönster
En slice_pattern tar bort noll eller fler element. Den får endast användas direkt i en list_pattern_clause, och sedan endast en gång i den klausulen.
slice_pattern
: '..' pattern?
;
En slice_pattern utan subpattern är kompatibel med alla typer som är kompatibla med en list_pattern. En slice_pattern med ett subpattern är kompatibelt med alla typer som kan räknas (§18.1) samt utsnittsbara (§18.1)– den har en tillgänglig indexerare som tar ett Range argument eller en tillgänglig Slice metod med två int parametrar. Om båda är närvarande är det förstnämnda att föredra. (Se §18.4.2 för information om implicit indexstöd.)
En slice_pattern fungerar som en riktig ignorera; Det innebär att inga provningar skall göras för ett sådant mönster. I stället påverkar det bara andra noder, nämligen längden och indexeraren. Ett mönster i formuläret expr is [1, .. var s, 3] motsvarar till exempel följande kod (om det är kompatibelt via explicit Index och Range support):
expr.Length is >= 2
&& expr[new Index(0, fromEnd: false)] is 1
&& expr[new Range(new Index(1, fromEnd: false), new Index(1, fromEnd: true))] is var s
&& expr[new Index(1, fromEnd: true)] is 3
Indatatypen för en slice_pattern är returtypen för den underliggande this[Range] metoden eller Slice metoden med två undantag: För strings och matriser string.SubstringRuntimeHelpers.GetSubArrayska respektive användas.
Exempel: Ett segmentmönster kan endast användas för att matcha element i början eller/och slutet av en indatasekvens.
Console.WriteLine(new[] { 1, 2, 3, 4, 5 } is [> 0, > 0, ..]); // True Console.WriteLine(new[] { 1, 1 } is [_, _, ..]); // True Console.WriteLine(new[] { 0, 1, 2, 3, 4 } is [> 0, > 0, ..]); // False Console.WriteLine(new[] { 1 } is [1, 2, ..]); // False Console.WriteLine(new[] { 1, 2, 3, 4 } is [.., > 0, > 0]); // True Console.WriteLine(new[] { 2, 4 } is [.., > 0, 2, 4]); // False Console.WriteLine(new[] { 2, 4 } is [.., 2, 4]); // True Console.WriteLine(new[] { 1, 2, 3, 4 } is [>= 0, .., 2 or 4]); // True Console.WriteLine(new[] { 1, 0, 0, 1 } is [1, 0, .., 0, 1]); // True Console.WriteLine(new[] { 1, 0, 1 } is [1, 0, .., 0, 1]); // Falseslutexempel
Exempel: En underordnad kan kapslas inom ett segmentmönster:
MatchMessage("aBBA"); // output: Message aBBA matches; inner part is BB. MatchMessage("apron"); // output: Message apron doesn't match. void MatchMessage(string message) { var result = message is ['a' or 'A', .. var s, 'a' or 'A'] ? $"Message {message} matches; inner part is {s}." : $"Message {message} doesn't match."; Console.WriteLine(result); } Validate(new[] { -1, 0, 1 }); // output: not valid Validate(new[] { -1, 0, 0, 1 }); // output: valid void Validate(int[] numbers) { var result = numbers is [< 0, .. { Length: 2 or 4 }, > 0] ? "valid" : "not valid"; Console.WriteLine(result); }slutexempel
11.3 Undersummor för mönster
I en switch-instruktion (§13.8.3) är det ett fel om ett ärendes mönster undersummas av föregående uppsättning obevakade (§13.8.3) fall. I ett växeluttryck (§12.12) är det ett fel om ett switch_expression_arm mönster undersummas av föregående uppsättning obevakadeswitch_expression_armmönster.
Obs! Detta innebär att alla indatavärden skulle ha matchats av något av de tidigare fallen eller armarna. slutkommentar 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 något av följande villkor gäller:
- Specifikationen för det mönstrets körningsbeteende är att matchar
PK. -
Pär en type_pattern för typenTochKär intenulloch körningstypenKärTeller en typ som härleds frånTeller en typ som implementerarT. -
Pär en relational_pattern med operatorn «op» och konstantv, och uttrycketK«op»vskulle utvärderas tilltrue. -
Pär en negated_patternnot P₁ochP₁skulle inte matchaK. -
Pär en conjunctive_patternP₁ and P₂och bådaP₁matcharKochP₂skulle matchaK. -
Pär en disjunctive_patternP₁ or P₂och skulle antingenP₁matchaKellerP₂matchaK. -
Pär en discard_pattern.
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). -
Pär en type_pattern för typenToch uppsättningen mönsterQär fullständig för typenT. -
Pär en relational_pattern med operatorn «op» och konstant värdev, och för varje värde av indatatypen som uppfyller relationen «op»vskulle ett mönster i uppsättningenQmatcha det värdet. -
Pär en disjunctive_patternP₁ or P₂och en uppsättning mönsterundersummorQP₁ochQundersummorP₂. -
Pär en conjunctive_patternP₁ and P₂och minst ett av följande undantag:QundersummorP₁ellerQundersummorP₂. -
Pär en negated_patternnot P₁ochQär fullständig för indatatypen med tanke på de värden som inte matchas avP₁. -
Pär en discard_pattern och uppsättningen mönsterQär fullständig för typen av mönsterindatavärde, och antingen är mönsterindatavärdet inte av en nullbar typ eller så matcharQnågot mönster inull. - Vissa mönster i
Qär en disjunctive_patternQ₁ or Q₂och att ersätta det mönstret medQ₁iQskulle ge en uppsättning som undersummarPeller ersätta den medQ₂skulle ge en uppsättning som undersummorP. - Vissa mönster i
Qär en negated_patternnot Q₁ochPskulle inte matcha något värde somQ₁skulle matcha.
Exempel: I följande växeluttryck undersummas ingen arm trots att armarna 1, 2 och 3 har samma mönster:
object x = 10; bool b = false; int y = x switch { int i when !b => 0, int i when b => 1, int i => 2, _ => 3 };Armar 1 och 2 har icke-konstanta vakter och är därför inte obevakade; endast arm 3 är obevakad med mönster
int i, vilket inte undersummar den sista_armen eftersom den inte matchar ett icke-värdeint, tillnullexempel . slutexempel
Undersumtionskontroll av list_patterns och slice_patterns fungerar precis som positionsmönster med ITuple (§11.2.5) motsvarande undermönster matchas efter position plus en ytterligare nod för testlängd.
Följande kod genererar till exempel ett fel eftersom båda mönstren ger samma DAG:
case [_, .., 1]: // expr.Length is >= 2 && expr[^1] is 1
case [.., _, 1]: // expr.Length is >= 2 && expr[^1] is 1
Olikt:
case [_, 1, ..]: // expr.Length is >= 2 && expr[1] is 1
case [.., 1, _]: // expr.Length is >= 2 && expr[^2] is 1
Med en viss längd är det möjligt att två underavsnitt refererar till samma element, i vilket fall ett test för det här värdet infogas i besluts-DAG.
- Till exempel
[_, >0, ..] or [.., <=0, _]blirlength >= 2 && ([1] > 0 || length == 3 || [^2] <= 0)där längdvärdet 3 innebär det andra testet. - Omvänt blir
[_, >0, ..] and [.., <=0, _]length >= 2 && [1] > 0 && length != 3 && [^2] <= 0där längdvärdet på 3 inte tillåter det andra testet.
Därför ska ett fel resultera i något liknande case [.., p]: case [p]: , eftersom samma element matchas i det andra fallet vid körning.
Om ett sektorundermönster matchar en lista eller ett längdvärde ska underordnad behandlas som om de vore ett direkt underordnat av den innehållande listan. Till exempel [..[1, 2, 3]] undersummar ett mönster i formuläret [1, 2, 3].
Följande antaganden görs om de medlemmar som används:
- Egenskapen som gör typen räknad antas alltid returnera ett icke-negativt värde, om och endast om typen är indexerbar. Mönstret
{ Length: -1 }kan till exempel aldrig matcha en matris. - Den medlem som gör typen utsnittsbar antas vara väluppfostrad. det vill: returvärdet är aldrig
nulloch att det är en korrekt delmängd av den innehållande listan.
Beteendet för en mönstermatchningsåtgärd är odefinierat om något av ovanstående antaganden inte gäller. [
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 - Ett mönster i
Qär ett deklarationsmönster för typenD, och det finns en identitetskonvertering, en implicit referenskonvertering eller en boxningskonvertering frånTtillD; eller - Vissa mönster i
Qär en type_pattern för typenD, och det finns en identitetskonvertering, en implicit referenskonvertering eller en boxningskonvertering frånTtillD; eller - Vissa mönster i
Qär en discard_pattern, eller - Mönstren i
Qinkluderar en kombination av relational_patterns och constant_patternvars intervall tillsammans täcker alla möjliga värden förTden underliggande typen som inte kan nollas. Förfloatochdoubletyper, detta inkluderarSystem.Double.NaNellerSystem.Single.NaNrespektive, eftersomNaNinte matchas av något relationsmönster; eller - Vissa mönster i
Qär en disjunctive_patternP₁ or P₂, och att ersätta det mönstret med bådeP₁ochP₂iQger en uppsättning som är fullständig förT; eller - Vissa mönster i
Qär en negated_patternnot P₁, och mönstren tillsammansQmed värdena som inte matchas avP₁täcker alla möjliga värden förT. En negated_patternnot P₁är fullständig i sig närP₁den inte matchar något möjligt värde förT; eller - Vissa mönster i
Qär en conjunctive_patternP₁ and P₂, och uppsättningen som endastP₁innehåller är fullständig förToch uppsättningen som endastP₂innehåller är fullständig förT.
Obs! När ett typmönster innehåller nullbara typer kan mönstret vara fullständigt för typen men ändå generera en varning eftersom typmönstret inte matchar ett
nullvärde. slutkommentar
Obs! För flyttalstyper är kombinationen av mönster
< 0och>= 0inte fullständig eftersom inget relationsmönster matcharNaN. En korrekt fullständig uppsättning skulle vara< 0,>= 0ochdouble.NaN(ellerfloat.NaN). slutkommentar
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