11 Wzorce i dopasowywanie wzorców
11.1 Ogólne
Wzorzec jest formą składniową, która może być używana z is
operatorem (§12.12.12) i w switch_statement (§13.8.3) w celu wyrażenia kształtu danych, względem których mają być porównywane dane przychodzące. Wzorzec jest testowany względem wyrażenia instrukcji switch lub względem relational_expression , który znajduje się po lewej stronie is
operatora, z których każdy jest określany jako wartość wejściowa wzorca.
Formularze wzorca 11.2
11.2.1 Ogólne
Wzorzec może mieć jedną z następujących form:
pattern
: declaration_pattern
| constant_pattern
| var_pattern
;
Declaration_pattern i var_pattern mogą 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 zastosowanie do typuT
, jeśli T
należy do 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
v
toTextReader
. Zmienna typuTextReader
nigdy 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
v
czasu kompilacji toobject
. Zmienna typuobject
może mieć wartość zgodną z odwołaniem:string
object 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.
Wzorzec deklaracji 11.2.2
Declaration_pattern służy do testowania, czy wartość ma dany typ, a jeśli test zakończy się pomyślnie, podaj wartość w zmiennej tego typu.
declaration_pattern
: type simple_designation
;
simple_designation
: single_variable_designation
;
single_variable_designation
: identifier
;
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.12.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 dopuszczanej do wartości null (§8.3.12). Ten formularz wzorca nigdy nie pasuje do null
wartości.
Uwaga: wyrażenie
e is T
typu is i wzorzece is T _
deklaracji są równoważne, gdyT
nie 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 identyfikatorem _
, oznacza odrzucenie (§9.2.9.1), 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). Jeśli simple_designation jest innym identyfikatorem, zostanie wprowadzona zmienna lokalna (§9.2.9) danego typu o nazwie danego 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 typemT
, jeśli istnieje konwersja tożsamości, niejawna lub jawna konwersja odwołań, konwersja boksu lub konwersja E
rozpaku z na T
, lub jeśli E
albo T
jest typem otwartym (§8.4.3). Wzorzec deklaracji nazewnictwa typu T
ma zastosowanie do każdego typuE
, dla którego E
wzorzec jest zgodny z T
.
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
Jest to błąd, jeśli typ jest typem wartości dopuszczanej do wartości null.
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)T
pasuje do wzorcaT2 id
typu, jeśli wartość jest inna niż null iT2
maT
wartość , lub jakiś podstawowy typ lub interfejsT
. Na przykład w fragmentie koduint? x = 3; if (x is int v) { /* code using v */ }
Warunek instrukcji
if
jesttrue
w czasie wykonywania, a zmiennav
przechowuje wartość3
typuint
wewnątrz bloku. 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 zastosowanie do typuT
, jeśli istnieje niejawna konwersja z wyrażenia stałego P
na typ T
.P
W przypadku wzorca P
stał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
P
pasuje do wartości e, jeśli wynik wyrażeniae == v
totrue
; w przeciwnym razie - wzorzec
P
pasuje do wartości e , jeśliobject.Equals(e, v)
zwraca wartośćtrue
.
Przykład: instrukcja
switch
w 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
;
Biorąc pod uwagę wartość wejściową wzorca (§11.1) e, jeśli oznaczenie jest identyfikatorem _
, oznacza odrzucenie (§9.2.9.1), 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). Jeśli oznaczenie jest innym identyfikatorem, 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 .
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 P
pasuje do stałej K
, jeśli specyfikacja zachowania środowiska uruchomieniowego tego wzorca jest P
zgodna z K
parametrem .
Zestaw wzorców Q
subsumuje wzorzec P
, jeśli którykolwiek z następujących warunków jest wstrzymany:
P
jest stałym wzorcem, a każdy z wzorców w zestawieQ
będzie zgodny zP
przekonwertowaną wartościąP
jest wzorcem var, a zestaw wzorcówQ
jest 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 wQ
elemecie jest zgodnynull
z .P
jest wzorcem deklaracji z typemT
, a zestaw wzorcówQ
jest wyczerpujący dla typuT
(§11.4).
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:
T
jest 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 bazowegoT
bez wartości null, jakiś wzorzec wQ
elemecie pasuje do tej wartości; lub- Wzorzec w pliku
Q
jest wzorcem var; lub - Wzorzec w pliku
Q
to wzorzec deklaracji typuD
, a istnieje konwersja tożsamości, niejawna konwersja odwołania lub konwersja boksu zT
naD
.
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