Sdílet prostřednictvím


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 je TextReader. Proměnná typu TextReader nemůže mít nikdy hodnotu, která je kompatibilní s string:

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 je object. Proměnná typu object může mít hodnotu, která je kompatibilní s string:

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 vzor e is T _ deklarace jsou ekvivalentní, pokud T 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ý ET 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 boxedNullable<T>) odpovídá vzoru TT2 id typu, pokud hodnota není null a T2 je T, nebo některé základního typu nebo rozhraní T. Například v fragmentu kódu

int? x = 3;
if (x is int v) { /* code using v */ }

Podmínka if příkazu je true za běhu a proměnná v obsahuje hodnotu 3 typu int 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 Pje 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 Podpovídá hodnotě e, pokud je e == vvýsledek výrazu true ;
  • 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 Pby se shodoval s konstantou K v případě, že P specifikace chování modulu runtime daného vzoru odpovídá K.

Sada vzorů Qpodsoustaví vzor P , pokud se drží některé z následujících podmínek:

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:

  1. 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ího Ttypu, která Q není nullable, by se určitý vzor shodoval s danou hodnotou;
  2. Určitý vzor v Q je var vzor; nebo
  3. V některých vzorech Q je vzor deklarace pro typ Da existuje převod identity, implicitní převod odkazu nebo krabicový převod z T na D.

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