11 Vzory a porovnávání vzorů
11.1 Obecné
Vzor je syntaktická forma, kterou lze použít s operátorem is
(§12.12.12) a v switch_statement (§13.8.3) k vyjádření tvaru dat, s nímž se mají příchozí data porovnávat. Vzor se testuje proti výrazu příkazu switch nebo proti relational_expression , který je na levé straně operátoru is
, z nichž každý se označuje jako vstupní hodnota vzoru.
11.2 Vzorové formuláře
11.2.1 Obecné
Vzor může mít jednu z následujících forem:
pattern
: declaration_pattern
| constant_pattern
| var_pattern
;
Výsledkem declaration_pattern a var_pattern může být deklarace místní proměnné.
Každý formulář vzoru definuje sadu typů pro vstupní hodnoty, na které lze vzor použít. Vzor P
se vztahuje na typ T
, pokud T
patří mezi typy, jejichž hodnoty se vzor může shodovat. Jedná se o chybu v době kompilace, pokud se v programu objeví vzorP
, který odpovídá vstupní hodnotě vzoru (§11.1T
pokud P
není použitelný pro T
.
Příklad: Následující příklad vygeneruje chybu v době kompilace, protože typ
v
kompilace jeTextReader
. Proměnná typuTextReader
nemůže mít nikdy hodnotu, která je kompatibilní sstring
:TextReader v = Console.In; // compile-time type of 'v' is 'TextReader' if (v is string) // compile-time error { // code assuming v is a string }
Následující příkaz však nevygeneruje chybu v době kompilace, protože typ
v
kompilace jeobject
. Proměnná typuobject
může mít hodnotu, která je kompatibilní sstring
:object v = Console.In; if (v is string s) { // code assuming v is a string }
end example
Každý formulář vzoru definuje sadu hodnot, pro které vzor odpovídá hodnotě za běhu.
11.2.2 Model deklarace
Declaration_pattern slouží k otestování, že hodnota má daný typ, a pokud je test úspěšný, zadejte hodnotu v proměnné tohoto typu.
declaration_pattern
: type simple_designation
;
simple_designation
: single_variable_designation
;
single_variable_designation
: identifier
;
Typ modulu runtime hodnoty je testován proti typu ve vzoru pomocí stejných pravidel uvedených v operátoru is-type (§12.12.12.1). Pokud je test úspěšný, vzor odpovídá této hodnotě. Jedná se o chybu v době kompilace, pokud je typ hodnoty null (§8.3.12). Tento vzorový formulář nikdy neodpovídá hodnotě null
.
Poznámka: Výraz
e is T
is-type a vzore is T _
deklarace jsou ekvivalentní, pokudT
není typu s možnou hodnotou null. koncová poznámka
Při zadání vzorové vstupní hodnoty (§11.1) e, je-li simple_designation identifikátor _
, znamená to zahození (§9.2.9.2) a hodnota e není nijak vázána. (I když deklarovaná proměnná s názvem _
může být v tomto okamžiku v oboru, tato pojmenovaná proměnná se v tomto kontextu nezobrazí.) Je-li simple_designation jiným identifikátorem, zavádějí se místní proměnné (§9.2.9.1) daného typu pojmenovaného daným identifikátorem. Tato místní proměnná má přiřazenou hodnotu vstupní hodnoty vzoru, pokud vzor odpovídá hodnotě.
Určité kombinace statického typu vstupní hodnoty vzoru a daného typu jsou považovány za nekompatibilní a výsledkem chyby v době kompilace. Hodnota statického typu E
je oznamována jako vzorek kompatibilní s typemT
, pokud existuje převod identity, implicitní nebo explicitní převod odkazu, převod boxingu nebo zrušení převodu z E
do T
, nebo je-li otevřený E
T
typ (§8.4.3). Deklarace vzoru pojmenování typu T
je použitelná pro každý typ E
, pro který E
je vzor kompatibilní s T
.
Poznámka: Podpora otevřených typů může být nejužitečnější při kontrole typů, které mohou být buď struktury, nebo typy tříd, a boxování je třeba se vyhnout. koncová poznámka
Příklad: Model deklarace je užitečný pro provádění testů typů běhu referenčních typů a nahrazuje idiom.
var v = expr as Type; if (v != null) { /* code using v */ }
s mírně stručnější
if (expr is Type v) { /* code using v */ }
end example
Jedná se o chybu, pokud je typ hodnoty nullable.
Příklad: Vzor deklarace lze použít k otestování hodnot typů s možnou hodnotou null: hodnota typu (nebo boxed
Nullable<T>
) odpovídá vzoruT
T2 id
typu, pokud hodnota není null aT2
jeT
, nebo některé základního typu nebo rozhraníT
. Například v fragmentu kóduint? x = 3; if (x is int v) { /* code using v */ }
Podmínka
if
příkazu jetrue
za běhu a proměnnáv
obsahuje hodnotu3
typuint
uvnitř bloku. end example
11.2.3 Konstantní vzor
Constant_pattern se používá k otestování hodnoty vstupní hodnoty vzoru (§11.1) s danou konstantní hodnotou.
constant_pattern
: constant_expression
;
Konstantní vzor P
se vztahuje na typ T
, pokud existuje implicitní převod z konstantního výrazu P
na typ T
.
U konstantního vzoru P
je převedená hodnota
- je-li typ vstupní hodnoty vzoru celočíselný typ nebo výčtový typ, konstantní hodnota vzoru převedena na tento typ; jinak
- pokud typ vstupní hodnoty vzoru je nullable verze celočíselného typu nebo výčtu typ, konstantní hodnota vzoru převedena na jeho základní typ; jinak
- hodnota konstantní hodnoty vzoru.
Při zadání vstupní hodnoty vzoru e a konstantního vzoru P
s převedenou hodnotou v,
- pokud e má celočíselný typ nebo výčtový typ nebo nulovou formu jednoho z nich a v má celočíselný typ, vzor
P
odpovídá hodnotě e, pokud jee == v
výsledek výrazutrue
; - vzor
P
odpovídá hodnotě e, pokud se vrátíobject.Equals(e, v)
.true
Příklad: Příkaz
switch
v následující metodě používá pět konstantních vzorů v popiscích písmen.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(...); } }
end example
11.2.4 Vzor var
Var_pattern odpovídá každé hodnotě. To znamená, že operace porovnávání vzorů s var_pattern vždy proběhne úspěšně.
Var_pattern platí pro každý typ.
var_pattern
: 'var' designation
;
designation
: simple_designation
;
Při zadání vzorové vstupní hodnoty (§11,1) e, je-li označení identifikátor _
, označuje zahození (§9.2.9.2) a hodnota e není nijak vázána. (I když deklarovaná proměnná s tímto názvem může být v tomto okamžiku v oboru, tato pojmenovaná proměnná není v tomto kontextu viditelná.) Pokud označení je jakýkoli jiný identifikátor, pak je hodnota e vázána na nově zavedenou místní proměnnou (§9.2.9.1) toho jména, jehož typ je statický typ e, a vstupní hodnota vzoru je přiřazena této místní proměnné.
Jedná se o chybu, pokud by se název var
sváže s typem, ve kterém se používá var_pattern .
11.3 Dílčí podsumpce vzorku
V příkazu switch se jedná o chybu, pokud je vzor případu podsoučet předchozí sadou nehlídaných případů (§13.8.3). Neformálně to znamená, že jakákoli vstupní hodnota by se shodovala s jednou z předchozích případů. Následující pravidla definují, kdy sada vzorů podsoustaví daný vzor:
Vzor P
by se shodoval s konstantou K
v případě, že P
specifikace chování modulu runtime daného vzoru odpovídá K
.
Sada vzorů Q
podsoustaví vzor P
, pokud se drží některé z následujících podmínek:
-
P
je konstantní vzor a libovolný ze vzorů v saděQ
by odpovídalP
převedené hodnotě. -
P
je vzor var a sada vzorů je vyčerpávající (§11.4) pro typ vstupní hodnoty vzoru (Q
) a buď vstupní hodnota vzoru není typu null, nebo by se shodoval nějaký vzor.Q
null
-
P
je vzor deklarace s typemT
a sada vzorůQ
je vyčerpávající pro typT
(§11.4).
11.4 Úplnost vzoru
Neformálně je sada vzorů pro typ vyčerpávající, pokud platí pro každou možnou hodnotu tohoto typu kromě hodnoty null, je možné použít nějaký vzor v sadě. Následující pravidla definují, kdy je sada vzorů pro typ vyčerpávající :
Sada vzorů Q
je T
, pokud jsou splněny některé z následujících podmínek:
-
T
je celočíselný nebo výčtový typ nebo verze jednoho z nich s možnou hodnotou null a pro každou možnou hodnotu základníhoT
typu, kteráQ
není nullable, by se určitý vzor shodoval s danou hodnotou; - Určitý vzor v
Q
je var vzor; nebo - V některých vzorech
Q
je vzor deklarace pro typD
a existuje převod identity, implicitní převod odkazu nebo krabicový převod zT
naD
.
Příklad:
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; } }
end example
ECMA C# draft specification