Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
11.1 Obecné
Vzor je syntaktická forma, kterou lze použít s operátorem is (§12.14.12), v switch_statement (§13.8.3) a v switch_expression (§12.11) vyjádřit tvar dat, proti kterým se mají příchozí data porovnávat. Vzory můžou být rekurzivní, takže se části dat můžou shodovat s dílčími vzory.
Model se testuje s hodnotou v řadě kontextů:
- V příkazu switch se vzor popisku případu testuje s výrazem příkazu switch.
- V operátoru is-pattern je vzor na pravé straně testován proti výrazu vlevo.
- Ve výrazu switch se vzorswitch_expression_arm testuje s výrazem na levé straně výrazu switch-expression.
- V vnořených kontextech se dílčí vzor testuje na základě hodnot načtených z vlastností, polí nebo indexovaných z jiných vstupních hodnot v závislosti na formuláři vzoru.
Hodnota, proti které se testuje, se nazývá 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
| positional_pattern
| property_pattern
| discard_pattern
;
Některé vzorymůžou vést k deklaraci 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.1 pokud T není použitelný pro P.
Příklad: Následující příklad vygeneruje chybu v době kompilace, protože typ
vkompilace jeTextReader. Proměnná typuTextReadernemůž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
vkompilace jeobject. Proměnná typuobjectmůže mít hodnotu, která je kompatibilní sstring:object v = Console.In; if (v is string s) { // code assuming v is a string }konec příkladu
Každý formulář vzoru definuje sadu hodnot, pro které vzor odpovídá hodnotě za běhu.
Pořadí vyhodnocení operací a vedlejších účinků během porovnávání vzorů (volání Deconstruct, přístupů k vlastnostem a vyvolání metod v System.ITuple) není zadáno.
11.2.2 Model deklarace
Declaration_pattern slouží k otestování, že hodnota má daný typ, a pokud je test úspěšný, volitelně zadat hodnotu v proměnné tohoto typu.
declaration_pattern
: type simple_designation
;
simple_designation
: discard_designation
| single_variable_designation
;
discard_designation
: '_'
;
single_variable_designation
: identifier
;
Simple_designation s tokenem _ se považuje za discard_designation, nikoli single_variable_designation.
Typ modulu runtime hodnoty se testuje s typem ve vzoru pomocí stejných pravidel uvedených v operátoru is-type (§12.14.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) nebo odkazový typ s možnou hodnotou null (§8.9.3). Tento vzorový formulář nikdy neodpovídá hodnotě null .
Poznámka: Výraz
e is Tis-type a vzore is T _deklarace jsou ekvivalentní, pokudTnení typu s možnou hodnotou null. koncová poznámka
Při zadání vzorové vstupní hodnoty (§11.1) e, pokud je simple_designationdiscard_designation, označuje 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í.) Pokud je simple_designationsingle_variable_designation, zanese se místní proměnná (§9.2.9) 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 */ }konec příkladu
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á vzoruTT2 idtypu, pokud hodnota není null aT2jeT, 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
ifpříkazu jetrueza běhu a proměnnávobsahuje hodnotu3typuintuvnitř bloku. Po bloku je proměnnávv oboru, ale rozhodně není přiřazena. konec příkladu
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 jee == vvýsledek výrazutrue; - vzor
Podpovídá hodnotě e, pokud se vrátíobject.Equals(e, v).true
Příklad: Příkaz
switchv 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(...); } }konec příkladu
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
| tuple_designation
;
tuple_designation
: '(' designations? ')'
;
designations
: designation (',' designation)*
;
Při zadání vzorové vstupní hodnoty (§11.1) e, pokud je označenídiscard_designation, označuje zahození (§9.2.9.2) a hodnota e není vázána na nic. (I když deklarovaná proměnná s tímto názvem může být v tomto okamžiku v oboru, tato pojmenovaná proměnná se v tomto kontextu nezobrazí.) V opačném případě, pokud je označenísingle_variable_designation, je hodnota e vázána na nově zavedenou místní proměnnou (§9.2.9) tohoto názvu, jehož typ je statickým typem e, a vstupní hodnota vzoru je přiřazena k 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 .
Je-li označenítuple_designation, je vzor ekvivalentní positional_pattern (§11.2.5) označení formuláře(var, ...
) kde jsou označenínalezena v tuple_designation. Například vzor var (x, (y, z)) je ekvivalentní (var x, (var y, var z)).
11.2.5 Poziční vzor
Positional_pattern zkontroluje, zda vstupní hodnota není null, vyvolá odpovídající Deconstruct metodu (§12.7) a provede další porovnávání vzorů s výslednými hodnotami. Podporuje také syntaxi vzoru řazenou kolekci členů (bez zadaného typu), pokud je typ vstupní hodnoty stejný jako typ obsahující Deconstruct, nebo pokud typ vstupní hodnoty je typ řazené kolekce členů, nebo pokud typ vstupní hodnoty je object nebo System.ITuple a typ modulu runtime výraz implementuje System.ITuple.
positional_pattern
: type? '(' subpatterns? ')' property_subpattern? simple_designation?
;
subpatterns
: subpattern (',' subpattern)*
;
subpattern
: pattern
| identifier ':' pattern
;
Vzhledem k porovnání vstupní hodnoty spodpatterny)typu( vzoru je metoda vybrána tak, že vyhledá v typu přístupné deklarace Deconstruct a vybere jednu z nich pomocí stejných pravidel jako pro dekonstrukční deklaraci.
Jedná se o chybu, pokud positional_pattern vynechá typ, má jeden podpattern bez identifikátoru, nemá žádné property_subpattern a nemá žádné simple_designation. To se nejednoznačným způsobem liší mezi constant_pattern , která je závorka a positional_pattern.
Chcete-li extrahovat hodnoty, které se mají shodovat se vzory v seznamu,
- Pokud je typ vynechán a typ vstupního výrazu je typ řazené kolekce členů, bude počet podpatternů stejný jako kardinalita řazené kolekce členů. Každý prvek řazené kolekce členů se porovná s odpovídajícím podpatternem a shoda bude úspěšná, pokud všechny tyto prvky proběhnou úspěšně. Pokud má některý podpatternidentifikátor, pak tento výraz pojmenuje prvek řazené kolekce členů na odpovídající pozici v typu řazené kolekce členů.
- Jinak, pokud vhodný
Deconstructexistuje jako člen typu, jedná se o chybu v době kompilace, pokud typ vstupní hodnoty není kompatibilní s typem. Za běhu se vstupní hodnota testuje proti typu. Pokud se to nezdaří, shoda pozičního vzoru selže. Pokud bude úspěšné, vstupní hodnota se převede na tento typ aDeconstructvyvolá se s čerstvými proměnnými generovanými kompilátorem pro příjem výstupních parametrů. Každá přijatá hodnota se shoduje s odpovídajícím podpatternem a shoda proběhne úspěšně, pokud jsou všechny tyto hodnoty úspěšné. Pokud má některý dílčí podpatternidentifikátor, pak tento parametr pojmenuje na odpovídající poziciDeconstruct. - V opačném případě, pokud je typ vynechán a vstupní hodnota je typu
objectnebo určitý typ, který lze převéstSystem.ITuplena implicitní převod odkazu, a žádný identifikátor se nezobrazí mezi podpatterny, pak shoda použijeSystem.ITuple. - V opačném případě se jedná o chybu v době kompilace.
Pořadí, ve kterém se podpatterny shodují za běhu, není zadáno a neúspěšná shoda se nemusí pokusit spárovat všechny podpatterny.
Příklad: Tady dekonstruujeme výsledek výrazu a porovnáme výsledné hodnoty s odpovídajícími vnořenými vzory:
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); }konec příkladu
Příklad: Názvy elementů řazené kolekce členů a parametry dekonstrukce lze použít v pozičním vzoru následujícím způsobem:
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); }Výstup je vytvořen.
Sum of [10 20 30] is 60konec příkladu
11.2.6 Vzor vlastností
Property_pattern zkontroluje, že vstupní hodnota není null, a rekurzivně odpovídá hodnotám extrahovaným použitím přístupných vlastností nebo polí.
property_pattern
: type? property_subpattern simple_designation?
;
property_subpattern
: '{' '}'
| '{' subpatterns ','? '}'
;
Jedná se o chybu, pokud některý dílčí podpatternproperty_pattern neobsahuje identifikátor.
Jedná se o chybu v době kompilace, pokud je typ hodnoty null (§8.3.12) nebo odkazový typ s možnou hodnotou null (§8.9.3).
Poznámka: Vzor kontroly hodnoty null se nevyučuje ze vzoru triviální vlastnosti. Pokud chcete zkontrolovat, jestli je řetězec
snenulový, můžete napsat některý z následujících formulářů:#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 {}) ...koncová poznámka Vzhledem k porovnání výrazu e s typem
{vzoruproperty_pattern_list}se jedná o chybu v době kompilace, pokud výraz e není kompatibilní se typem T určeným typem. Pokud typ chybí, předpokládá se, že se jedná o statický typ e. Každý identifikátor, který se nachází na levé straně jeho property_pattern_list, určí přístupnou čitelnou vlastnost nebo pole T. Pokud simple_designation property_pattern existuje, deklaruje proměnnou vzoru typu T.
Za běhu se výraz testuje proti T. Pokud se to nezdaří, vzor vlastnosti se nezdaří a výsledek je false. Pokud je to úspěšné, každé property_subpattern pole nebo vlastnost se přečte a jeho hodnota se shoduje s odpovídajícím vzorem. Výsledek celé shody je false pouze v případě, že výsledek některého z těchto výsledků je false. Pořadí, ve kterém se podpatterny shodují, není zadáno a neúspěšná shoda nemusí testovat všechny podpatterny za běhu. Pokud je shoda úspěšná a simple_designationproperty_pattern je single_variable_designation, deklarovaná proměnná se přiřadí odpovídající hodnotě.
Property_pattern lze použít k porovnávání vzorů s anonymními typy.
Příklad:
var o = ...; if (o is string { Length: 5 } s) ...konec příkladu
Příklad: Kontrola typu za běhu a deklarace proměnné lze přidat do vzoru vlastnosti následujícím způsobem:
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."), };Výstup je vytvořen.
Hello Hi! 12345 abckonec příkladu
11.2.7 Zahodit vzor
Každý výraz odpovídá vzoru zahození, což vede k zahození hodnoty výrazu.
discard_pattern
: '_'
;
Jedná se o chybu v době kompilace použití vzoru zahození v relational_expressionrelational_expression formulářeisnebo jako vzor switch_label.
Poznámka: V těchto případech, aby se shodovaly s libovolným výrazem, použijte var_pattern s zahozením
var _. koncová poznámka
Příklad:
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, };Výstup je vytvořen.
5.0 0.0 0.0Zde se vzor zahození používá ke zpracování
nulla jakékoli celočíselné hodnotě, která nemá odpovídající člen výčtuDayOfWeek. To zaručuje, žeswitchvýraz zpracovává všechny možné vstupní hodnoty. konec příkladu
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:
-
Pje konstantní vzor a libovolný ze vzorů v saděQby odpovídalPpřevedené hodnotě. -
Pje 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.Qnull -
Pje vzor deklarace s typemTa sada vzorůQje 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 , pokud jsou splněny některé z následujících podmínek:
-
Tje 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íhoTtypu, kteráQnení nullable, by se určitý vzor shodoval s danou hodnotou; - Určitý vzor v
Qje var vzor; nebo - V některých vzorech
Qje vzor deklarace pro typDa existuje převod identity, implicitní převod odkazu nebo krabicový převod zTnaD.
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; } }konec příkladu
ECMA C# draft specification