Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
11.1 Ogólne
Wzorzec jest formą składniową, która może być używana z is operatorem (§12.15.12), w switch_statement (§13.8.3) i w switch_expression (§12.12) w celu wyrażenia kształtu danych, względem których mają być porównywane dane przychodzące. Wzorce mogą być rekursywne, dzięki czemu części danych mogą być dopasowane do wzorców podrzędnych.
Wzorzec jest testowany względem wartości w wielu kontekstach:
- W instrukcji switch wzorzec etykiety wielkości liter jest testowany względem wyrażenia instrukcji switch.
- W operatorze is-pattern wzorzec po prawej stronie jest testowany względem wyrażenia po lewej stronie.
- W wyrażeniu przełącznika wzorzecswitch_expression_arm jest testowany względem wyrażenia po lewej stronie wyrażenia przełącznika.
- W kontekstach zagnieżdżonych wzorzec jest testowany względem wartości pobranych z właściwości, pól lub indeksowanych z innych wartości wejściowych, w zależności od formularza wzorca.
Wartość, względem której testowany jest wzorzec, jest nazywana wartością wejściową wzorca.
Formularze wzorca 11.2
11.2.1 Ogólne
Wzorzec może mieć jedną z następujących form:
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 ')'
;
Produkcja '(' pattern ')' umożliwia ujęcie wzorca w nawiasy, aby wymusić kolejność oceny między wzorcami połączonymi przy użyciu jednego z logical_patterns.
Niektóre wzorcemogą spowodować deklarację zmiennej lokalnej.
Każdy formularz wzorca definiuje zestaw typów dla wartości wejściowych, do których można zastosować wzorzec. Wzorzec P ma typów, których wartości mogą być zgodne ze wzorcem. Jest to błąd czasu kompilacji, jeśli wzorzec pojawia się w programie, aby dopasować wartość wejściową wzorca P (§11.1) typu T , jeśli P nie ma zastosowania do T.
Przykład: Poniższy przykład generuje błąd czasu kompilacji, ponieważ typ czasu kompilacji
vtoTextReader. Zmienna typuTextReadernigdy nie może mieć wartości zgodnej z elementemstring:TextReader v = Console.In; // compile-time type of 'v' is 'TextReader' if (v is string) // compile-time error { // code assuming v is a string }Jednak następujące polecenie nie generuje błędu czasu kompilacji, ponieważ typ czasu kompilacji
vtoobject. Zmienna typuobjectmoże mieć wartość zgodną z odwołaniem:stringobject v = Console.In; if (v is string s) { // code assuming v is a string }przykład końcowy
Każdy formularz wzorca definiuje zestaw wartości, dla których wzorzec pasuje do wartości w czasie wykonywania.
Kolejność oceny operacji i skutków ubocznych podczas dopasowywania wzorca (wywołania do , dostęp do Deconstructwłaściwości i wywołania metod w programie System.ITuple) nie jest określony.
Wzorzec deklaracji 11.2.2
Declaration_pattern służy do testowania, czy wartość ma dany typ i, jeśli test zakończy się pomyślnie, opcjonalnie podaj wartość w zmiennej tego typu.
declaration_pattern
: type simple_designation
;
simple_designation
: discard_designation
| single_variable_designation
;
discard_designation
: '_'
;
single_variable_designation
: identifier
;
Simple_designation z tokenem _ uznaje się za discard_designation, a nie single_variable_designation.
Typ środowiska uruchomieniowego wartości jest testowany względem typu we wzorcu przy użyciu tych samych reguł określonych w operatorze is-type (§12.15.12.1). Jeśli test zakończy się pomyślnie, wzorzec pasuje do tej wartości. Jest to błąd czasu kompilacji, jeśli typ jest typem wartości dopuszczalnej wartości null (§8.3.12) lub typem odwołania dopuszczanym do wartości null (§8.9.3). Ten formularz wzorca nigdy nie pasuje do null wartości.
Uwaga: wyrażenie
e is Ttypu is i wzorzece is T _deklaracji są równoważne, gdyTnie jest typem dopuszczalnym wartości null. notatka końcowa
Biorąc pod uwagę wartość wejściową wzorca (§11.1) e, jeśli simple_designation jest discard_designation, oznacza odrzucenie (§9.2.9.2), a wartość e nie jest powiązana z niczym. (Chociaż zadeklarowana zmienna o nazwie _ może być w tym momencie w zakresie, ta nazwana zmienna nie jest widoczna w tym kontekście). W przeciwnym razie, jeśli simple_designation jest single_variable_designation, wprowadzana jest zmienna lokalna (§9.2.9) danego typu o nazwie podanego identyfikatora. Ta zmienna lokalna ma przypisaną wartość wartości wejściowej wzorca, gdy wzorzec jest zgodny z wartością.
Niektóre kombinacje statycznego typu wartości wejściowej wzorca i danego typu są uznawane za niezgodne i powodują błąd czasu kompilacji. Wartość typu E statycznego jest zgodna ze wzorcem zgodnym z typem T , jeśli istnieje konwersja tożsamości, niejawna lub jawna konwersja odwołań, konwersja boksu, konwersja rozpaku lub niejawna lub jawna konwersja typu wartości dopuszczającej wartość null z E do T, lub jeśli ET albo jest typem otwartym (§8.4.3). Wzorzec deklaracji nazewnictwa typu T ma zastosowanie do.
Uwaga: Obsługa typów otwierania może być najbardziej przydatna podczas sprawdzania typów, które mogą być typami struktur lub klas, i należy unikać tworzenia pól. notatka końcowa
Przykład: Wzorzec deklaracji jest przydatny do wykonywania testów typu czasu wykonywania typów odwołań i zastępuje idiom
var v = expr as Type; if (v != null) { /* code using v */ }z nieco bardziej zwięzłym
if (expr is Type v) { /* code using v */ }przykład końcowy
Przykład: Wzorzec deklaracji może służyć do testowania wartości typów dopuszczanych do wartości null: wartość typu
Nullable<T>(lub pole)Tpasuje do wzorcaT2 idtypu, jeśli wartość jest inna niż null iT2maTwartość , lub jakiś podstawowy typ lub interfejsT. Na przykład w fragmentie koduint? x = 3; if (x is int v) { /* code using v */ }Warunek instrukcji
ifjesttruew czasie wykonywania, a zmiennavprzechowuje wartość3typuintwewnątrz bloku. Po zablokowaniu zmiennavznajduje się w zakresie, ale na pewno nie jest przypisana. przykład końcowy
Wzorzec stałej 11.2.3
Constant_pattern służy do testowania wartości wartości wejściowej wzorca (§11.1) względem danej wartości stałej.
constant_pattern
: constant_expression
;
Wzorzec stałej ma P typu, jeśli istnieje niejawna konwersja z wyrażenia stałego T na typ P.T
W przypadku wzorca Pstałego jego przekonwertowana wartość to
- jeśli typ wartości wejściowej wzorca jest typem całkowitym lub typem wyliczeniowym, stała wartość wzorca przekonwertowana na ten typ; inaczej
- jeśli typ wartości wejściowej wzorca jest wersją typu całkowitego dopuszczaną do wartości null lub typem wyliczenia, stała wartość wzorca przekonwertowana na jego typ bazowy; inaczej
- wartość stałej wartości wzorca.
Biorąc pod uwagę wartość wejściową wzorca e i stały wzorzec P z przekonwertowaną wartością v,
- jeśli e ma typ całkowity lub typ wyliczeniowy, albo możliwą do wartości null formę jednego z nich, a v ma typ całkowity, wzorzec
Ppasuje do wartości e, jeśli wynik wyrażeniae == vtotrue; w przeciwnym razie - wzorzec
Ppasuje do wartości e , jeśliobject.Equals(e, v)zwraca wartośćtrue.
Przykład: instrukcja
switchw poniższej metodzie używa pięciu wzorców stałych w etykietach przypadków.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(...); } }przykład końcowy
Wzorzec wariancja 11.2.4
Var_pattern pasuje do każdej wartości. Oznacza to, że operacja dopasowywania wzorca z var_pattern zawsze kończy się powodzeniem.
Var_pattern ma zastosowanie do każdego typu.
var_pattern
: 'var' designation
;
designation
: simple_designation
| tuple_designation
;
tuple_designation
: '(' designations? ')'
;
designations
: designation (',' designation)*
;
Biorąc pod uwagę wartość wejściową wzorca (§11.1) e, jeśli oznaczenie jest discard_designation, oznacza odrzucenie (§9.2.9.2), a wartość e nie jest powiązana z niczym. (Mimo że zadeklarowana zmienna o tej nazwie może znajdować się w zakresie w tym momencie, ta nazwana zmienna nie jest widoczna w tym kontekście). W przeciwnym razie, jeśli oznaczenie jest single_variable_designation, w czasie wykonywania wartość e jest powiązana z nowo wprowadzoną zmienną lokalną (§9.2.9) tej nazwy, której typem jest typ statyczny e, a wartość wejściowa wzorca jest przypisana do tej zmiennej lokalnej.
Jest to błąd, jeśli nazwa var będzie wiązać się z typem , w którym jest używana var_pattern .
Jeśli oznaczenie jest tuple_designation, wzorzec jest odpowiednikiem positional_pattern (§11.2.5) (var formularza, ...
) gdzie oznaczenias znajdują się w tuple_designation. Na przykład wzorzec jest odpowiednikiem var (x, (y, z)).(var x, (var y, var z))
11.2.5 Wzorzec pozycyjny
Positional_pattern sprawdza, czy wartość wejściowa nie nulljest , wywołuje odpowiednią Deconstruct metodę (§12.7) i wykonuje dalsze dopasowywanie wzorca dla wartości wynikowych. Obsługuje również składnię wzorca przypominającą krotkę (bez podanego typu), gdy typ wartości wejściowej jest taki sam jak typ zawierający Deconstruct, lub jeśli typ wartości wejściowej jest typem krotki, lub jeśli typ wartości wejściowej to object lub System.ITuple typ środowiska uruchomieniowego wyrażenia implementuje System.ITuplewartość .
positional_pattern
: type? '(' subpatterns? ')' property_subpattern? simple_designation?
;
subpatterns
: subpattern (',' subpattern)*
;
subpattern
: pattern
| identifier ':' pattern
;
Biorąc pod uwagę dopasowanie wartości wejściowej dopodwzorców(typu) wzorca, metoda jest wybierana przez wyszukiwanie w typie dostępnych deklaracji Deconstruct i wybranie jednej z nich przy użyciu tych samych reguł co dla deklaracji dekonstrukcji.
Jest to błąd, jeśli positional_pattern pomija typ, ma jeden podwzorca bez identyfikatora, nie ma property_subpattern i nie ma simple_designation. To rozbicie między constant_pattern , który jest nawiasem i positional_pattern.
Aby wyodrębnić wartości, które mają być zgodne z wzorcami na liście,
- Jeśli typ zostanie pominięty, a typ wyrażenia wejściowego jest typem krotki, liczba podwzorców musi być taka sama jak kardynalność krotki. Każdy element krotki jest zgodny z odpowiednim podwzorcą, a dopasowanie powiedzie się, jeśli wszystkie te elementy powiedzą się. Jeśli jakikolwiek podwzorca ma identyfikator, nazwa to element krotki w odpowiedniej pozycji w typie krotki.
- W przeciwnym razie, jeśli odpowiedni
Deconstructelement istnieje jako element członkowski typu, jest to błąd czasu kompilacji, jeśli typ wartości wejściowej nie jest zgodny ze wzorcem z typem. W czasie wykonywania wartość wejściowa jest testowana względem typu. Jeśli to się nie powiedzie, dopasowanie wzorca pozycyjnego zakończy się niepowodzeniem. Jeśli to się powiedzie, wartość wejściowa jest konwertowana na ten typ iDeconstructjest wywoływana ze świeżymi zmiennymi wygenerowanymi przez kompilator w celu odbierania parametrów wyjściowych. Każda odebrana wartość jest zgodna z odpowiednim podwzorcą, a dopasowanie powiedzie się, jeśli wszystkie te elementy powiedzą się. Jeśli jakikolwiek podwzorca ma identyfikator, nazwa parametruDeconstructw odpowiedniej pozycji . - W przeciwnym razie, jeśli typ zostanie pominięty, a wartość wejściowa jest typu
objectlub jakiś typ, który można przekonwertować naSystem.ITupleprzez niejawną konwersję odwołania, a żaden identyfikator nie pojawia się wśród podwzorców, dopasowanie używaSystem.ITuplemetody . - W przeciwnym razie wzorzec jest błędem czasu kompilacji.
Kolejność dopasowania podwzorców w czasie wykonywania jest nieokreślona, a dopasowanie nie powiodło się, może nie być zgodne ze wszystkimi podwzorcami.
Przykład: w tym miejscu dekonstrukujemy wynik wyrażenia i dopasujemy wartości wynikowe do odpowiednich zagnieżdżonych wzorców:
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); }przykład końcowy
Przykład: Nazwy elementów krotki i parametrów Deconstruct mogą być używane w wzorcu pozycyjnym w następujący sposób:
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); }Generowane dane wyjściowe są następujące:
Sum of [10 20 30] is 60przykład końcowy
Wzorzec właściwości 11.2.6
Property_pattern sprawdza, czy wartość wejściowa nie nulljest wartością , a rekursywnie pasuje do wartości wyodrębnionych przez użycie dostępnych właściwości lub pól.
property_pattern
: type? property_subpattern simple_designation?
;
property_subpattern
: '{' '}'
| '{' subpatterns ','? '}'
;
Jest to błąd, jeśli jakikolwiek podwzorcaproperty_pattern nie zawiera identyfikatora.
Jest to błąd czasu kompilacji, jeśli typ jest typem wartości dopuszczalnej wartości null (§8.3.12) lub typem odwołania dopuszczanym do wartości null (§8.9.3).
Uwaga: Wzorzec sprawdzania wartości null wypada ze wzorca właściwości trywialnych. Aby sprawdzić, czy ciąg
sjest inny niż null, można napisać dowolny z następujących formularzy:#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 {}) ...notatka końcowa
Biorąc pod uwagę dopasowanie wyrażenia e dopodwzorców{typu} wzorca, jest to błąd czasu kompilacji, jeśli wyrażenie e nie jest zgodne ze wzorcem z typem T wyznaczonym przez typ. Jeśli typ jest nieobecny, przyjmuje się, że typ jest statycznym typem e. Każdy z identyfikatorów wyświetlanych po lewej stronie jego podwzorców wyznacza dostępną czytelną właściwość lub pole T. Jeśli simple_designationproperty_pattern jest obecny, deklaruje zmienną wzorca typu T.
W czasie wykonywania wyrażenie jest testowane względem języka T. Jeśli to się nie powiedzie, dopasowanie wzorca właściwości zakończy się niepowodzeniem, a wynikiem jest false. Jeśli to się powiedzie, każde pole lub właściwość property_subpattern jest odczytywane, a jego wartość jest dopasowywana do odpowiadającego mu wzorca. Wynik całego dopasowania jest false tylko wtedy, gdy wynik któregokolwiek z nich to false. Kolejność dopasowania podwzorców nie jest określona, a dopasowanie nie powiodło się, może nie przetestować wszystkich podwzorców w czasie wykonywania. Jeśli dopasowanie powiedzie się, a simple_designationproperty_pattern jest single_variable_designation, zadeklarowana zmienna zostanie przypisana do dopasowanej wartości.
Property_pattern może służyć do dopasowywania wzorca do typów anonimowych.
Przykład:
var o = ...; if (o is string { Length: 5 } s) ...przykład końcowy
Przykład: Sprawdzanie typu czasu wykonywania i deklaracja zmiennej można dodać do wzorca właściwości w następujący sposób:
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."), };Generowane dane wyjściowe są następujące:
Hello Hi! 12345 abcprzykład końcowy
11.2.7 Odrzuć wzorzec
Każde wyrażenie jest zgodne ze wzorcem odrzucenia, co powoduje odrzucenie wartości wyrażenia.
discard_pattern
: '_'
;
Jest to błąd czasu kompilacji, aby użyć wzorca odrzucenia w relational_expression wzorca formularza relational_expressionis lub jakowzorzecswitch_label.
Uwaga: W takich przypadkach, aby dopasować dowolne wyrażenie, użyj var_pattern z odrzuceniem
var _. notatka końcowa
Przykład:
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, };Generowane dane wyjściowe są następujące:
5.0 0.0 0.0Tutaj wzorzec odrzucenia jest używany do obsługi
nulli wszystkich wartości całkowitych, które nie mają odpowiedniegoDayOfWeekelementu członkowskiego wyliczenia. Gwarantuje to, żeswitchwyrażenie obsługuje wszystkie możliwe wartości wejściowe. przykład końcowy
Wzorzec typu 11.2.8
Type_pattern służy do testowania, czy wartość wejściowa wzorca (§11.1) ma określony typ.
type_pattern
: type
;
Wzorzec typu nazewnictwa typu Tma zastosowanie do każdego typu E , dla którego Ewzorzec jest zgodny z T (§11.2.2).
Typ środowiska uruchomieniowego wartości jest testowany względem typu przy użyciu tych samych reguł określonych w operatorze is-type (§12.15.12.1). Jeśli test zakończy się pomyślnie, wzorzec pasuje do tej wartości. Jest to błąd czasu kompilacji, jeśli typ jest typem dopuszczalnym wartości null. Ten formularz wzorca nigdy nie pasuje do null wartości.
Wzorzec relacyjny 11.2.9
Relational_pattern służy do relacyjnej testowania wartości wejściowej wzorca (§11.1) względem wartości stałej.
relational_pattern
: '<' relational_expression
| '<=' relational_expression
| '>' relational_expression
| '>=' relational_expression
;
Do obliczenia wartości stałej wymagane jest relational_expression w relational_pattern .
Wzorce relacyjne obsługują operatory <relacyjne , <=, >i >= we wszystkich wbudowanych typach, które obsługują takie operatory relacyjne binarne z obydwoma operandami o tym samym typie: sbyte, intshortdoublefloatdecimalnintbyteuintnuintushortlongulongchari wyliczenia.
Relational_pattern ma zastosowanie do typuT, jeśli odpowiedni wbudowany operator relacyjny binarny jest zdefiniowany z obydwoma operandami typu T, lub jeśli istnieje jawna konwersja dopuszczana do wartości null lub unboxing z T typu wyrażenia stałego.
Jest to błąd czasu kompilacji, jeśli wyrażenie zwróci wartość double.NaN, float.NaNlub stałą null.
Gdy wartość wejściowa ma typ, dla którego jest zdefiniowany odpowiedni wbudowany operator relacyjny binarny, ocena tego operatora jest traktowana jako znaczenie wzorca relacyjnego. W przeciwnym razie wartość wejściowa jest konwertowana na typ wyrażenia stałego przy użyciu jawnej konwersji dopuszczającej wartość null lub odboxingu. Jest to błąd czasu kompilacji, jeśli taka konwersja nie istnieje. Wzorzec jest uznawany za niezgodny, jeśli konwersja nie powiedzie się. Jeśli konwersja powiedzie się, wynikiem operacji dopasowywania wzorca jest ocena wyrażenia e «op» v , w którym e jest konwertowane dane wejściowe, «op» jest operatorem relacyjnym i v jest wyrażeniem stałym.
Przykład:
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", };Generowane dane wyjściowe są następujące:
Too high Unknown Acceptableprzykład końcowy
11.2.10 Wzorzec logiczny
Logical_pattern służy do negowania wyniku dopasowania wzorca lub łączenia wyników wielu dopasowań wzorca przy użyciu kombinacji (and) lub rozsyłania (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, andi or są zbiorczo nazywane operatorami wzorców.
Negated_pattern pasuje, jeśli negowany wzorzec nie jest zgodny i odwrotnie.
Conjunctive_pattern wymaga dopasowania obu wzorców.
Disjunctive_pattern wymaga dopasowania obu wzorców. W przeciwieństwie do ich odpowiedników operatorów językowych && i ||, and i ornie są operatorami zwarciowymi.
Jest to błąd czasu kompilacji dla zmiennej wzorca, która ma być zadeklarowana pod operatorem not lub or wzorca.
Uwaga: ponieważ ani
notornie może utworzyć określonego przypisania dla zmiennej wzorca, jest to błąd deklarowania jednego w tych pozycjach. notatka końcowa
W conjunctive_patterntyp wejściowy drugiego wzorca jest zawężany przez typ zawężający wymagania pierwszego wzorca .and
Zawężony typ wzorca P jest definiowany w następujący sposób:
- Jeśli
Pjest wzorcem typu, zawężony typ jest typem typu wzorca typu. - W przeciwnym razie, jeśli
Pjest wzorcem deklaracji, zawężony typ jest typem typu wzorca deklaracji. - W przeciwnym razie, jeśli
Pjest wzorcem rekursywnym, który daje jawny typ, zawężonego typu jest ten typ. - W przeciwnym razie, jeśli
Pjest dopasowywany za pośrednictwem reguł wITuplepositional_pattern (§11.2.5), zawężony typ to .System.ITuple - W przeciwnym razie, jeśli jest stałym wzorcem, w
Pktórym stała nie jest stałą null i gdzie wyrażenie nie ma stałej konwersji wyrażenia na typ danych wejściowych, zawężony typ jest typem stałej. - W przeciwnym razie, jeśli
Pjest wzorcem relacyjnym, w którym wyrażenie stałe nie ma stałej konwersji wyrażenia na typ wejściowy, zawężony typ jest typem stałej. - W przeciwnym razie, jeśli
Pjest wzorcemor, zawężony typ jest typowym typem zawężonego typu podwzorców, jeśli taki typ wspólny istnieje. W tym celu algorytm wspólnego typu uwzględnia tylko konwersje tożsamości, boksu i niejawnych odwołań oraz uwzględnia wszystkie podwzory sekwencjiorwzorców (ignorując wzorce nawiasów). - W przeciwnym razie, jeśli
Pjest wzorcemand, zawężony typ jest zawężonym typem odpowiedniego wzorca. Ponadto zawęziony typ wzorca po lewej stronie jest typem wejściowym odpowiedniego wzorca. - W przeciwnym razie zawęziony typ
PjestPtypem wejściowym.
Uwaga: zgodnie z gramatyką
notma pierwszeństwo przedandwartością , która ma pierwszeństwo przedor. Można to jawnie wskazać lub zastąpić za pomocą nawiasów. notatka końcowa
Gdy wzorzec pojawia się po prawej stronie is, zakres wzorca jest określany przez gramatykę; w rezultacie operatory andwzorca , ori not w obrębie wzorca wiążą się ściślej niż operatory &&logiczne , ||i ! poza wzorcem.
Przykład:
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", };Generowane dane wyjściowe są następujące:
High Too low Acceptableprzykład końcowy
Przykład:
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}."), };Generowane dane wyjściowe są następujące:
winter autumn springprzykład końcowy
Przykład:
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}");Generowane dane wyjściowe są następujące:
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: Trueprzykład końcowy
11.3 Podsumpcja wzorca
W instrukcji switch jest to błąd, jeśli wzorzec sprawy jest podsumowywany przez poprzedni zestaw niestrzeżonych przypadków (§13.8.3). Nieformalnie oznacza to, że każda wartość wejściowa byłaby zgodna z jedną z poprzednich przypadków. Następujące reguły definiują, kiedy zestaw wzorców subsumuje określony wzorzec:
Wzorzec Ppasuje do stałej K , jeśli którykolwiek z następujących warunków jest wstrzymany:
- specyfikacją zachowania środowiska uruchomieniowego tego wzorca jest to, że
Pjest zgodna zKparametrem . -
Pjest type_pattern typuTi nienulljest,Ka typKśrodowiska uruchomieniowego jestTlub typ pochodzący zTlub typu, który implementujeT. -
Pjest relational_pattern z operatorem «op» i stałąv, a wyrażenieK«op»vzwróci wartość .true -
Pjest negated_patternnot P₁iP₁nie pasujeKdo . -
Pjest conjunctive_patternP₁ and P₂, a obaP₁będą zgodneKiP₂pasują doK. -
Pjest disjunctive_patternP₁ or P₂iP₁alboKpasuje, alboP₂pasujeKdo . -
Pjest discard_pattern.
Zestaw wzorców Qsubsumuje wzorzec P , jeśli którykolwiek z następujących warunków jest wstrzymany:
-
Pjest stałym wzorcem, a każdy z wzorców w zestawieQbędzie zgodny zPprzekonwertowaną wartością -
Pjest wzorcem var, a zestaw wzorcówQjest wyczerpujący (§11.4) dla typu wartości wejściowej wzorca (§11.1), a wartość wejściowa wzorca nie jest typu dopuszczalnego wartości null lub jakiś wzorzec wQelemecie jest zgodnynullz . -
Pjest wzorcem deklaracji z typemT, a zestaw wzorcówQjest wyczerpujący dla typuT(§11.4). -
Pjest type_pattern typuT, a zestaw wzorcówQjest wyczerpujący dla typuT. -
Pjest relational_pattern z operatorem «op» i wartością stałą , a dla każdej wartościvtypu wejściowego spełniającego relację «op»v, jakiś wzorzec w zestawieQbędzie pasował do tej wartości. -
Pto disjunctive_patternP₁ or P₂oraz zestaw podsumowaniaP₁iQpodsumowaniaP₂wzorcówQ. -
Pjest conjunctive_patternP₁ and P₂i co najmniej jedna z następujących blokad:QpodsumyP₁, lubQpodsumyP₂. -
Pjest negated_patternnot P₁iQjest wyczerpujący dla typu wejściowego, biorąc pod uwagę tylko wartości, które nie są zgodne przezP₁. -
Pjest discard_pattern , a zestaw wzorcówQjest wyczerpujący dla typu wartości wejściowej wzorca, a wartość wejściowa wzorca nie jest typu dopuszczalnego wartości null lub jakiś wzorzec wQelemecie jest zgodnynullz . - Jakiś wzorzec w
Qpliku to disjunctive_patternQ₁ or Q₂i zastąpienie tego wzorca elementemQ₁inQspowoduje uzyskanie zestawu, który subsumujeP, lub zastąpienie go wartościąQ₂, spowoduje uzyskanie zestawu, który subsumujeP. - Wzorzec w pliku
Qto negated_patternnot Q₁iPnie pasuje do żadnej zgodnej wartościQ₁.
11.4 Wyczerpującość wzorca
Nieformalnie zestaw wzorców jest wyczerpujący dla typu, jeśli dla każdej możliwej wartości tego typu innej niż null, jakiś wzorzec w zestawie ma zastosowanie. Następujące reguły określają, kiedy zestaw wzorców jest wyczerpujący dla typu:
Zestaw wzorców Q jest wyczerpujący dla typu T , jeśli którykolwiek z następujących warunków jest wstrzymany:
-
Tjest typem całkowitym lub wyliczeniowym albo wersją dopuszczającą wartość null jednej z tych wartości i dla każdej możliwej wartości typu bazowegoTbez wartości null, jakiś wzorzec wQelemecie pasuje do tej wartości; lub - Wzorzec w pliku
Qjest wzorcem var; lub - Wzorzec w pliku
Qjest wzorcem deklaracji dla typuD, a istnieje konwersja tożsamości, niejawna konwersja odwołania lub konwersja boksu zTnaD; lub - Wzorzec w pliku
Qto type_pattern typuD, a istnieje konwersja tożsamości, niejawna konwersja odwołania lub konwersja boksu zTnaD; lub - Wzorzec w pliku
Qto discard_pattern; lub - Wzorce w programie
Qobejmują kombinację relational_patterns i constant_patterns, których zakresy łącznie obejmują każdą możliwą wartość typu bazowegoTbez wartości null. W przypadkufloattypów idoubleobejmujeSystem.Double.NaNto lubSystem.Single.NaNodpowiednio, ponieważNaNnie jest zgodne z żadnym wzorcem relacyjnym; lub - Wzorzec w obiekcie
Qto disjunctive_patternP₁ or P₂, a zastąpienie tego wzorca parametrem zarównoP₁, jak iP₂wQparametrze daje zestaw wyczerpujący dlaTelementu ; lub - Wzorzec w pliku
Qto negated_patternnot P₁, a wzorce wQpołączeniu z wartościami, które nie są zgodne zP₁każdą możliwą wartościąT. Negated_patternnot P₁jest wyczerpująca, gdyP₁nie pasuje do możliwejTwartości ; lub - Wzorzec w pliku
Qto conjunctive_patternP₁ and P₂, a zestaw zawierający tylkoP₁jest wyczerpujący, a zestaw zawierający tylkoP₂element jest wyczerpującyTdla elementuT.
Uwaga: jeśli wzorzec typu zawiera typy dopuszczające wartość null, wzorzec może być wyczerpujący dla typu, ale nadal generuje ostrzeżenie, ponieważ wzorzec typu nie będzie zgodny z wartością
null. notatka końcowa
Uwaga: w przypadku typów zmiennoprzecinkowych kombinacja wzorców
< 0i>= 0nie jest wyczerpująca, ponieważ żaden wzorzec relacyjny nie pasuje doNaNklasy . Prawidłowym zestawem wyczerpującym jest< 0,>= 0idouble.NaN(lubfloat.NaN). notatka końcowa
Przykład:
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; } }przykład końcowy
ECMA C# draft specification