11 Minták és minták egyeztetése

11.1 Általános

Az operátorral is (12.15.12.§), egy switch_statement (13.8.3. §) és egy switch_expression (12.12. §) mintával lehet leírni azokat az adatokat, amelyekhez a bejövő adatokat össze kell hasonlítani. A minták beágyazhatók, és az adatok egyes részei almintákkal egyeznek.

A minta több környezetben is tesztelve van egy értéken:

  • Egy switch_statement egy switch_labelmintáját a switch_statement selector_expression teszteli.
  • Az is-pattern operátorral a jobb oldalon lévő minta a bal oldali kifejezésen lesz tesztelve.
  • Egy switch_expression egy switch_expression_armmintáját teszteli a switch_expression bal oldalán lévő kifejezéssel.
  • Beágyazott környezetekben az alminta a tulajdonságokból, mezőkből vagy más bemeneti értékekből indexelt értékeken van tesztelve a minta űrlapjától függően.

Azt az értéket, amely alapján a minta tesztelése történik, a minta bemeneti értékének nevezzük.

11.2 Mintaalakok

11.2.1 Általános

Egy minta a következő űrlapok egyikével rendelkezhet:

pattern
    : logical_pattern
    ;

primary_pattern
    : parenthesized_pattern
    | declaration_pattern
    | constant_pattern
    | var_pattern
    | positional_pattern
    | property_pattern
    | discard_pattern
    | type_pattern
    | relational_pattern
    | logical_pattern
    | list_pattern
    | slice_pattern
    ;

Az '(' pattern ')' éles környezet lehetővé teszi, hogy zárójelek közé zárjon egy mintát, hogy kényszerítse a minták közötti kiértékelési sorrendet a logical_patternegyikével kombinálva.

Ha a bemenet szintaktikailag felismerhető constant_pattern és positional_pattern is, akkor a constant_pattern kell kiválasztani.

Egyes mintákhelyi változó deklarációját eredményezhetik.

Minden mintaűrlap meghatározza a minta által alkalmazható bemeneti értékek típusait. A minta P akkor , ha T azon típusok közé tartozik, amelyek értékei megegyezhetnek a mintával. Fordítási idejű hiba, ha egy minta P egy olyan programban jelenik meg, amely megfelel egy minta bemeneti értékének (T. §), ha P az nem alkalmazható.T

Példa: Az alábbi példa fordítási időt eredményez, mert a fordítási idő típusa v .TextReader Egy típusú TextReader változó soha nem rendelkezhet olyan értékkel, amely hivatkozással stringkompatibilis:

TextReader v = Console.In; // compile-time type of 'v' is 'TextReader'
if (v is string) // compile-time error
{
    // code assuming v is a string
}

Az alábbiak azonban nem okoznak fordítási időt, mert a fordítási idő típusa v .object Egy típusváltozó object olyan értékkel rendelkezhet, amely hivatkozással kompatibilis a következőkkel string:

object v = Console.In;
if (v is string s)
{
    // code assuming v is a string
}

záró példa

Minden mintaűrlap meghatározza azokat az értékeket, amelyek esetében a minta futásidőben megegyezik az értékkel.

Nincs megadva a műveletek és a mellékhatások kiértékelési sorrendje a mintaegyeztetés során (a hívások Deconstruct, a tulajdonsághozzáférések és a tagok meghívásai System.Runtime.CompilerServices.ITuple).

11.2.2 Deklarációs minta

A declaration_pattern annak tesztelésére szolgál, hogy egy értéknek van-e egy adott típusa, és ha a teszt sikeres, az adott típusú változó értékének megadása opcionálisan.

declaration_pattern
    : type simple_designation
    ;
simple_designation
    : discard_designation
    | single_variable_designation
    ;
discard_designation
    : '_'
    ;
single_variable_designation
    : identifier
    ;

Egy simple_designation felismerésekor, ha a discard_designation és single_variable_designation alternatíva is alkalmazható, akkor az előbbit kell választani.

Megjegyzés: Az ANTLR automatikusan választja a megadott lehetőséget a simple_designation alternatíváinak sorrendje miatt. végjegyzet

Az érték futtatókörnyezeti típusát a rendszer a mintában szereplő típussal teszteli az is-type operátorban megadott szabályokkal (12.15.12.1. §). Ha a teszt sikeres, a minta megfelel ennek az értéknek. Fordítási idejű hiba, ha a típus null értékű (8.3.12. §) vagy null értékű hivatkozástípus (8.9.3. §). Ez a mintaűrlap soha nem egyezik meg egy null értékkel.

Megjegyzés: Az is-type kifejezés e is T és a deklarációs minta e is T _ egyenértékű, ha T nem null értékű típus. végjegyzet

Ha a minta bemeneti értéke (11.1. §) e, ha a simple_designationegy discard_designation, és elvetést jelöl (9.2.9.2. §), az e érték nem kötődik semmihez. Ellenkező esetben, ha a simple_designationegy single_variable_designation, a rendszer bevezet egy helyi változót (9.2.9. §) az adott azonosító által elnevezett adott típusból. Ez a helyi változó a minta bemeneti értékének értékét rendeli hozzá, ha a minta megfelel az értéknek.

Megjegyzés: A declaration_pattern ezen kezelése _ eltér a mintaként írt önálló _ típustól (11.2.7.§): az utóbbi esetben a hatókörön belüli állandó vagy típus neve _– ha van ilyen – nem rejtett. végjegyzet

A típusnak E a típussal Tkompatibilis mintának kell lennie, ha létezik identitásátalakítás, implicit vagy explicit referenciakonvertálás, dobozos átalakítás, nem dobozos átalakítás, implicit vagy explicit null értékű érték típus konvertálása a típusról a formátumra ET, vagy ha vagy ET nyitott típus (8.4.3. §). A típus T elnevezésére szolgáló deklarációs minta (11.2.1. §) minden olyan típusra Ealkalmazható, amelynek E mintája kompatibilis a .T Fordítási idejű hiba, ha egy típust T elnevező deklarációs minta egy olyan minta bemeneti értékének (11.1. §) felel meg, amelynek statikus típusa E nem kompatibilis a mintával T.

Megjegyzés: A nyitott típusok támogatása leginkább akkor lehet hasznos, ha olyan típusokat ellenőriz, amelyek lehetnek strukturált vagy osztálytípusok, és kerülni kell a boxolást. végjegyzet

Példa: A deklarálási minta hasznos a referenciatípusok futásidejű típustesztjeihez, és lecseréli az idiómát

var v = expr as Type;
if (v != null) { /* code using v */ }

a kissé tömörebb

if (expr is Type v) { /* code using v */ }

záró példa

Példa: A deklarálási minta használható null értékű értékek tesztelésére: egy típus ( Nullable<T> vagy egy dobozos T) érték megfelel egy típusmintának T2 id , ha az érték nem null értékű, és T2 az T, vagy a típus valamilyen alaptípusa Tvagy felülete. Például a kódtöredékben

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

Az utasítás állapota if futásidőben vantrue, és a változó v a blokkon belül tárolja a típus 3 értékétint. A blokk után a változó v hatókörben van, de nem feltétlenül van hozzárendelve. záró példa

11.2.3 Állandó minta

Egy constant_pattern egy minta bemeneti értékének (11.1. §) az adott állandó értéken való tesztelésére szolgál.

constant_pattern
    : constant_expression
    ;

Az állandó minta P akkor , ha implicit átalakítás történik az állandó kifejezésből T a típusba P.

Állandó minta Pesetén a konvertált érték a következő:

  • ha a minta bemeneti értékének típusa integráltípus vagy számtípus, akkor a minta állandó értéke erre a típusra lesz konvertálva; egyébként
  • ha a minta bemeneti értéke egy integrál- vagy számtípus null értékű verziója, a minta állandó értéke az alapul szolgáló típussá alakul át; egyébként
  • a minta állandó értékének értéke.

Az e mintául szolgáló bemeneti érték és a konvertált v értékkel rendelkező állandó mintaP,

  • ha e integráltípussal vagy számtípussal rendelkezik, vagy az egyiknek null értékű formája van, és v integráltípussal rendelkezik, a minta P megfelel az e értéknek, ha a kifejezés e == vtrueeredménye; egyébként
  • ha e típus System.Span<char> vagy System.ReadOnlySpan<char>, és v állandó sztring, és a v nem rendelkezik nullállandó értékkel, akkor a minta megfeleltetésnek minősül, ha System.MemoryExtensions.SequenceEqual<char>(e, System.MemoryExtensions.AsSpan(v)) visszaadja true; ellenkező esetben
  • a minta Pmegfelel az e értéknek, ha object.Equals(e, v) visszaadjatrue.

Példa: A switch következő metódusban szereplő utasítás öt állandó mintát használ a kis- és nagybetűk címkéiben.

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(...);
    }
}

záró példa

11.2.4 Var minta

Egy var_patternminden értéknek megfelel . Ez azt jelzi, hogy egy mintaegyeztetés mindig sikeres var_pattern.

A var_patternminden típusra alkalmazható.

var_pattern
    : 'var' designation
    ;
designation
    : simple_designation
    | tuple_designation
    ;
tuple_designation
    : '(' designations? ')'
    ;
designations
    : designation (',' designation)*
    ;

A minta bemeneti értéke (11.1.§) e, ha a megjelölésdiscard_designation, akkor elvetésnek (9.2.9.2. §) jelöli, és az e érték semmihez nem kötődik. (Bár az ilyen nevű deklarált változók a hatókörben lehetnek, az elnevezett változó ebben a kontextusban nem látható.) Ellenkező esetben, ha a megjelöléssingle_variable_designation, futásidőben az e érték egy újonnan bevezetett helyi változóhoz (9.2.9. §) van kötve, amelynek típusa az e statikus típus, és a minta bemeneti értéke hozzá van rendelve ehhez a helyi változóhoz.

Hiba, ha a név var olyan típushoz kötődik, amelyben egy var_pattern használ.

Ha a megjelöléstuple_designation, a minta egyenértékű az űrlap megjelölésének(var (11.2.5.§), ... ) ahol a megjelölésaz tuple_designation belül található. A minta var (x, (y, z)) például egyenértékű a következő értékével (var x, (var y, var z)): .

11.2.5 Pozícióminta

A positional_pattern ellenőrzi, hogy a bemeneti érték nem null, kiolvas egy értéksorozatot belőle, és megfelel az egyes kinyert értékeknek egy megfelelő alpatteren. Az értékek kinyerése háromféleképpen történik: a bemenetet rekordként kezeli, metódus meghívásával Deconstruct vagy a bemenet System.Runtime.CompilerServices.ITupleindexelésével.

Megjegyzés: Az itt használt Deconstruct adatok eltérnek a 12.7. végjegyzet

positional_pattern
    : type? '(' subpatterns? ')' property_subpattern? simple_designation?
    ;
subpatterns
    : subpattern (',' subpattern)*
    ;
subpattern
    : pattern
    | subpattern_name ':' pattern
    ;
subpattern_name
    : identifier
    | subpattern_name '.' identifier
    ;

Legyen n a zárójelek között megjelenő alpatterekszáma. Az egyező stratégia fordításkor van kiválasztva a következő esetek sorrendjének alkalmazásával; az első eset, amelynek feltételei teljesülnek, és a fennmaradó eseteket nem veszik figyelembe. Az eset kiválasztása után a stratégia véglegesítése megtörténik: az ebben az esetben megadott fordítási idő hibát a program jelenti, és az egyeztetés nem kerül át egy későbbi esetre.

  1. Rekordforma. Ha a típus nincs megadva, és a bemeneti érték statikus típusa rekordtípus (8.3.11. §), vagy ha a bemeneti érték egy rekordkonstans (12.8.6. §), akkor ez az eset érvényes. Fordítási idő hiba, ha n nem egyenlő az adott típus aritásával. Futásidőben a rendszer minden egyes elemet egyeztet a megfelelő alhálózattal; az egyezés sikeres lesz, ha ezek mindegyike sikeres. Ha bármely alpattern rendelkezik azonosítóval, az azonosítónak el kell neveznie a tuple elemet a típus megfelelő helyén.
  2. Deconstruct form. Ellenkező esetben, ha valamelyik típus jelen van, vagy a típus ki van hagyva, és a bemeneti érték statikus típusa tartalmaz egy akadálymentes Deconstruct módszert (12.7. §), akkor ez az eset érvényes. Írja be a Dtípust , ha a típus jelen van; egyéb esetben hagyja , hogy a D legyen a bemeneti érték statikus típusa. A DeconstructD-ből a dekonstruálási deklarációhoz hasonló túlterhelésfeloldási szabályokkal választunk ki egy metódust, azzal a további követelménysel, hogy a paraméterek száma outn-vel egyenlő legyen; fordítási idő hiba, ha nincs ilyen módszer. Ha a típus jelen van, akkor fordítási idejű hiba, ha a bemeneti érték statikus típusa nem mintával kompatibilis (11.2.2.2. §) típussal; futásidőben a bemeneti érték típus alapján van tesztelve, és ha a teszt sikertelen, a pozícióminta egyezése meghiúsul. Ellenkező esetben a bemeneti érték D értékké alakul, és a rendszer meghívja a kiválasztott Deconstruct metódust a paramétereket fogadó out friss változókkal. Minden fogadott érték megfelel a megfelelő alhálózatnak, és az egyezés sikeres lesz, ha ezek mindegyike sikeres. Ha bármely alhálózat rendelkezik azonosítóval, az azonosítónak a paramétert a megfelelő pozícióban kell megadnia Deconstruct.
  3. ITuple űrlap. Ellenkező esetben, ha a típus nincs megadva, egyetlen alpatter sem rendelkezik azonosítóval, és a bemeneti érték objectstatikus típusa , System.Runtime.CompilerServices.ITuplevagy egy olyan típus, amely implicit hivatkozási konverzióval System.Runtime.CompilerServices.ITuplerendelkezik, akkor ez az eset érvényes. Futásidőben a bemeneti érték tesztelésenullSystem.Runtime.CompilerServices.ITuplenem a következő: ha a teszt sikertelen, a pozícióminta egyezése meghiúsul. Ellenkező esetben az érték tulajdonsága Length beolvasva, és ha nem egyenlő n értékkel, a pozícióminta egyezése meghiúsul. Ellenkező esetben minden i 1-től n-ig, a bemeneti érték i − 1 értékkel való indexelésével kapott érték az i-edikallaphoz van igazítva, és az egyezés sikeres lesz, ha mindegyik sikeres.
  4. Ellenkező esetben nincs eset, és a positional_pattern fordítási idő hiba.

Az alhálózatok futásidőben való egyeztetésének sorrendje nem meghatározott, és előfordulhat, hogy egy sikertelen egyezés nem próbálja meg az összes alhálózatot egyeztetni.

Példa: Itt egy kifejezés eredményét bontjuk fel, és az eredményként kapott értékeket a megfelelő beágyazott mintákkal egyeztetjük:

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);
}

záró példa

Példa: A rekordelemek és a Deconstruct paraméterek neve a következőképpen használható egy pozíciómintában:

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);
}

A létrehozott kimenet a következő:

Sum of [10 20 30] is 60

záró példa

11.2.6 Tulajdonságminta

A property_pattern ellenőrzi, hogy a bemeneti érték nem null, és rekurzívan egyezik-e az akadálymentes tulajdonságok vagy mezők használatával kinyert értékekkel.

property_pattern
    : type? property_subpattern simple_designation?
    ;
property_subpattern
    : '{' '}'
    | '{' subpatterns ','? '}'
    ;

Hiba, ha egy property_pattern egyik alpatterje sem tartalmaz subpattern_name.

Fordítási idejű hiba, ha a típus null értékű (8.3.12. §) vagy null értékű hivatkozástípus (8.9.3. §).

Megjegyzés: A null-ellenőrző minta kiesik egy triviális tulajdonságmintából. Ha ellenőrizni szeretné, hogy a sztring s nem null értékű-e, az alábbi űrlapok bármelyikét megírhatja:

#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 {}) ...

végjegyzet

Az e kifejezésnek a mintatípus{alpattereivel} való egyezése miatt fordítási időhiba, ha az e kifejezés nem mintával kompatibilis (11.2.2.2. §) a típus szerint kijelölt T típussal. Ha a típus hiányzik, a rendszer feltételezi, hogy a típus az e statikus típusa. Minden subpattern_name, amely az alhálózatok bal oldalán jelenik meg, a T elérhető olvasható tulajdonságát vagy mezőjét kell kijelölnie. Ha a property_pattern simple_designation jelen van, egy T típusú mintaváltozót deklarál.

Futásidőben a kifejezés tesztelése T-n történik. Ha ez nem sikerül, akkor a tulajdonságminta egyezik, és az eredmény a következő false. Ha sikerül, akkor minden property_subpattern mező vagy tulajdonság beolvasva, és az értéke megfelel a megfelelő mintának. A teljes egyezés eredménye csak akkor vanfalse, ha ezek bármelyikének eredménye .false Az alhálózatok egyeztetési sorrendje nincs megadva, és előfordulhat, hogy egy sikertelen egyezés nem teszteli az összes alhálózatot futásidőben. Ha az egyezés sikeres, és a property_pattern simple_designationegy single_variable_designation, a deklarált változó hozzárendeli a megfeleltetett értéket.

A property_pattern a névtelen típusokkal való mintaegyezésre használható.

A subpattern_name hivatkozhatnak beágyazott tagra. Ilyen esetben az egyes névkeresések fogadója az előző tag T₀ típusa, a property_patternbemeneti típusától kezdve. Ha A T null értékű típus, akkor a T₀ a mögöttes típus, ellenkező esetben a T₀ értéke T. Az űrlap { Prop1.Prop2: pattern } mintázata például pontosan egyenértékű a következővel { Prop1: { Prop2: pattern } }:

Megjegyzés: Ez magában foglalja a null ellenőrzést, ha a T null értékű vagy hivatkozástípus. Ez a null-ellenőrzés azt jelenti, hogy az elérhető beágyazott tulajdonságok a T₀ tulajdonságai lesznek, nem pedig a T tulajdonsága. Mivel az ismétlődő tagútvonalak engedélyezettek, a mintaegyezés összeállítása kihasználhatja a minták gyakori részeit. végjegyzet

Példa:

var o = ...;
if (o is string { Length: 5 } s) ...

záró példa

Példa: Egy futásidejű típusellenőrzés és egy változódeklaráció hozzáadható egy tulajdonságmintához az alábbiak szerint:

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."),
};

A létrehozott kimenet a következő:

Hello
Hi!
12345
abc

záró példa

11.2.7 Elvetési minta

Minden kifejezés megegyezik az elvetési mintával, ami a kifejezés elvetésének értékét eredményezi.

discard_pattern
    : '_'
    ;

Ha a szintaktikai környezet lehetővé teszi a mintát, ha a jogkivonat _simple_name (12.8.4. §) feloldana egy akadálymentes állandóra vagy egy típusra, akkor _a rendszer nem kezeli discard_pattern. Helyette:

  • Ha _ akadálymentes állandóra van feloldva, a _ rendszer constant_pattern (11.2.3. §) értelmezi, amelynek állandókifejezése ez az állandó.
  • Ha _ egy típusra van feloldva, akkor az operátor jobb oldalán is a szerkezet relational_expressionis _ is-type operátorként (12.15.12.1.1.1.) értelmezi a rendszer az adott típuson végzett tesztelést. Bármely más szintaktikai kontextusban, amely elismeri a mintát, _ a típus nélküli feloldás önmagában nem érvényes minta, azonban előfordulhat, _ hogy egy declaration_patterntípusaként (például _ x) vagy más, típusnak kifejezetten nevező mintaformákban jelenik meg.

Ez a szabály megőrzi a visszafelé kompatibilitást az elvetési minta bevezetése előtt típusként vagy azonosítóként definiált _ kóddal. Ha _ nem akadálymentes állandóra vagy típusra (például helyi változóra, paraméterre, mezőre vagy metódusra) oldja fel a megoldást, a szabály nem érvényes, és _discard_pattern marad.

Megjegyzés: Ez hasonló a 11.2.4. §-ban szereplő szabályhozvar, azzal a kivételrel, hogy _ a hatókörön belüli állandó vagy típus esetében a hiba helyett az adott _ deklarációra mutató hivatkozásként kell értelmezni. végjegyzet

Ha az előző szabály alkalmazása után a jogkivonat _ továbbra is discard_pattern, akkor fordítási időhiba, hogy a discard_patternaz űrlapis relational_expressionmintarelational_expression teljes mintájaként vagy egy switch_label teljes mintájaként jelenik meg. A discard_pattern azonban egy beágyazási minta alpatterjeként is megjelenhetnek (például egy positional_pattern vagy property_patternalpatterjeként).

Megjegyzés: Ezekben az esetekben a kifejezések egyeztetéséhez használjon var_pattern elvetéssel var _. végjegyzet

Példa:

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,
};

A létrehozott kimenet a következő:

5.0
0.0
0.0

Itt egy elvetési mintát használunk a kezeléshez null , és minden olyan egész számértéket, amely nem rendelkezik az DayOfWeek enumerálás megfelelő tagjával. Ez garantálja, hogy a switch kifejezés minden lehetséges bemeneti értéket kezel. záró példa

Példa: Az alábbiak azt szemléltetik, hogy a hatókörön belüli konstans neve _ hogyan változtatja meg egy _ kar értelmezését egy switch kifejezésben. A WithoutUnderscorekar _ egy discard_pattern , és minden értéknek megfelel. Ebben WithUnderscoreaz esetben a hatókörön belüli állandó _ miatt a _ kar olyan constant_pattern lesz értelmezve, amely csak az értéknek 0felel meg .

static string WithoutUnderscore(int n) => n switch
{
    1 => "one",
    _ => "other",
};

static string WithUnderscore(int n)
{
    const int _ = 0;
    return n switch
    {
        1 => "one",
        _ => "zero",
        var x => "other: " + x,
    };
}

záró példa

11.2.8 Típusminta

Egy type_pattern annak ellenőrzésére szolgál, hogy a minta bemeneti értéke (11.1. §) egy adott típussal rendelkezik-e.

type_pattern
    : type
    ;

A típus T elnevezésére szolgáló típusminta minden olyan típusraE alkalmazható, amelynek EmintájaT kompatibilis (11.2.2.2. §).

Az érték futtatókörnyezettípusát az is-type operátorban megadott szabályokkal teszteli a rendszer (12.15.12.1. §). Ha a teszt sikeres, a minta megfelel ennek az értéknek. Fordítási idejű hiba, ha a típus null értékű. Ez a mintaűrlap soha nem egyezik meg egy null értékkel.

11.2.9 Relációs minta

A relational_pattern a minta bemeneti értékének (11.1.§) relációs tesztelésére szolgál egy állandó értéken.

relational_pattern
    : '<'  relational_expression
    | '<=' relational_expression
    | '>'  relational_expression
    | '>=' relational_expression
    ;

A relational_pattern relational_expression állandó értékre kell kiértékelni.

A relációs minták támogatják a relációs operátorokat , , , és < az összes olyan beépített típust, amely támogatja az ilyen bináris relációs operátorokat, és mindkét operandus azonos típusú: <=, >, >=, sbyte, byteshortushortintuintlongulongcharfloatdoubleés számokat. decimalnintnuint

Fordítási időhiba, ha constant_expression, double.NaNfloat.NaNvagy null_literal.

Ha a bemeneti érték olyan típussal rendelkezik, amelyhez egy megfelelő beépített bináris relációs operátor van meghatározva, az operátor kiértékelése a relációs minta jelentése. Ellenkező esetben a bemeneti érték a constant_expression típusává lesz konvertálva explicit null értékű vagy nem dobozos átalakítással. Fordítási idejű hiba, ha nincs ilyen átalakítás. Fordítási idejű hiba, ha a bemeneti típus egy olyan típusparaméter, amely korlátozott vagy egy típus öröklődik, System.Numerics.INumberBase<T> és a bemeneti típus nem rendelkezik megfelelő beépített bináris relációs operátor definiálásával. A minta nem egyezik, ha az átalakítás sikertelen. Ha az átalakítás sikeres, a mintaegyeztetési művelet eredménye a konvertált bemenetet tartalmazó e «op» v kifejezés e kiértékelésének eredménye, az "op" a relációs operátor, és v a constant_expression.

Példa:

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",
};

A létrehozott kimenet a következő:

Too high
Unknown
Acceptable

záró példa

11.2.10 Logikai minta

A logical_pattern egy mintaegyezés eredményének tagadására, vagy több mintaegyezés eredményének egyesítésére szolgál kötőszó (and) vagy tiltás (or) használatával.

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, andés or együttesen mintaoperátoroknak nevezzük őket.

A negated_pattern akkor egyeznek, ha a negated minta nem egyezik, és fordítva. A conjunctive_pattern mindkét mintának meg kell egyeznie. A disjunctive_pattern mindkét mintát meg kell egyeznie. Ellentétben a nyelvi operátor megfelelőivel, &&|| és andornem rövidzárlatú operátorok.

Fordítási idő hiba, ha egy mintaváltozót egy vagy not minta or operátor alatt deklarálnak.

Megjegyzés: Mivel a mintaváltozókhoz nem notor lehet határozott hozzárendelést létrehozni, hiba az ilyen pozíciók egyikének deklarálása. végjegyzet

Egy conjunctive_pattern a második minta bemeneti típusát az első minta típusszűkítési követelményei szűkítik and. A minta P a következőképpen van definiálva:

  • Ha P típusminta, akkor a szűkített típus a típusminta típusának típusa.
  • Ellenkező esetben, ha P deklarációs minta, a szűkített típus a deklarációs minta típusának típusa.
  • Ellenkező esetben, ha P egy rekurzív minta explicit típust ad, akkor a leszűkített típus az a típus.
  • Ellenkező esetben, ha P egy ITuple szabályai (11.2.5. §) alapján egyeznek meg, a szűkített típus a típusSystem.ITuple.
  • Ellenkező esetben, ha P állandó minta, ahol az állandó nem null állandó, és ahol a kifejezés nem rendelkezik állandó kifejezéskonvertálással a bemeneti típusra, akkor a leszűkített típus az állandó típusa.
  • Ellenkező esetben, ha P olyan relációs minta, amelyben az állandó kifejezés nem rendelkezik állandó kifejezéskonvertálással a bemeneti típusra, a szűkített típus az állandó típusa.
  • Ellenkező esetben, ha P minta or , akkor a keskenyített típus az alhálózatok szűkített típusának közös típusa , ha létezik ilyen közös típus. Ebből a célból a közös típusú algoritmus csak identitás-, boxing- és implicit referenciakonverziókat vesz figyelembe, és figyelembe veszi a minták sorozatának or összes alpatterét (figyelmen kívül hagyva a zárójeles mintákat).
  • Ellenkező esetben, ha P minta and , akkor a szűkített típus a megfelelő minta szűkített típusa . Ezenkívül a bal minta szűkített típusa a jobb minta bemeneti típusa .
  • Ellenkező esetben a leszűkített típusP a Pbemeneti típus.

Megjegyzés: Ahogy a nyelvtan is jelzi, not elsőbbséget élvez a következővel szembenandor: Ez zárójelek használatával explicit módon jelezhető vagy felülírható. végjegyzet

Ha a minta a jobb oldalon isjelenik meg, a minta mértékét a nyelvtan határozza meg; ennek eredményeképpen a minta operátorai andor, és not a mintán belül szorosabban kötődnek, mint a logikai operátorok &&, ||és ! a mintán kívül.

Példa:

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",
};

A létrehozott kimenet a következő:

High
Too low
Acceptable

záró példa

Példa:

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}."),
};

A létrehozott kimenet a következő:

winter
autumn
spring

záró példa

Példa:

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}");

A létrehozott kimenet a következő:

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: True

záró példa

11.2.11 Listaminta

A list_pattern egy lista vagy tömb elemeinek sorozatával egyezik.

list_pattern
    : list_pattern_clause simple_designation?
    ;

list_pattern_clause
    : '[' (pattern (',' pattern)* ','?)? ']'
    ;

A list_pattern kompatibilis minden olyan típussal, amely megszámlálható (18.1. §) és indexelhető (18.1. §) – olyan akadálymentes indexelővel rendelkezik, amely argumentumként, Index vagy egy egyetlen int paraméterrel rendelkező akadálymentes indexelővel rendelkezik. Ha mindkét indexelő jelen van, az előbbi előnyben részesül. (Az implicit indextámogatás részleteiért lásd a 18.4.2. cikket .)

Az űrlap expr is [1, 2, 3] mintája megegyezik a következő kóddal:

expr.Length is 3
&& expr[new Index(0, fromEnd: false)] is 1
&& expr[new Index(1, fromEnd: false)] is 2
&& expr[new Index(2, fromEnd: false)] is 3

Példa:

int[] numbers = { 1, 2, 3 };

Console.WriteLine(numbers is [1, 2, 3]);  // True
Console.WriteLine(numbers is [1, 2, 4]);  // False
Console.WriteLine(numbers is [1, 2, 3, 4]);  // False
Console.WriteLine(numbers is [0 or 1, <= 2, >= 3 and not 7]);  // True

záró példa

Az elvetési minta (11.2.7. §) egyetlen elemnek felel meg.

Példa:

List<int> numbers = new() { 1, 2, 3 };

if (numbers is [_, var second, _])
{
    Console.WriteLine($"The second element is {second}.");
}

záró példa

11.2.12 Szeletminta

Egy slice_pattern nullát vagy több elemet elvet. Közvetlenül csak egy list_pattern_clause szabad használni, és ebben a záradékban legfeljebb egyszer.

slice_pattern
    : '..' pattern?
    ;

Az alpatter nélküli slice_pattern kompatibilis minden olyan típussal, amely kompatibilis a list_pattern. Az alpatternnel rendelkező slice_pattern kompatibilis minden olyan típussal, amely megszámlálható (18.1. §) és szeletelhető (18.1. §) – egy akadálymentes indexelővel rendelkezik, amely Range argumentumként, vagy két Slice paraméterrel rendelkező akadálymentes int metódussal rendelkezik. Ha mindkettő jelen van, az előbbi előnyben részesül. (Az implicit indextámogatás részleteiért lásd a 18.4.2. cikket .)

A slice_pattern úgy viselkednek, mint egy megfelelő elvetés; azaz ilyen mintát nem lehet tesztelni. Ehelyett csak a többi csomópontot, nevezetesen a hosszt és az indexelőt érinti. Az űrlap expr is [1, .. var s, 3] mintája például egyenértékű a következő kóddal (ha explicit Index és Range támogatással kompatibilis):

expr.Length is >= 2
&& expr[new Index(0, fromEnd: false)] is 1
&& expr[new Range(new Index(1, fromEnd: false), new Index(1, fromEnd: true))] is var s
&& expr[new Index(1, fromEnd: true)] is 3

A slice_pattern bemeneti típusa az alapul szolgáló this[Range] vagy Slice metódus visszatérési típusa két kivétellel: s és tömbök esetén string, string.Substring illetve RuntimeHelpers.GetSubArraytömbök esetén.

Példa: A szeletminta csak a bemeneti sorozat elején vagy végén használható elemek egyeztetésére.

Console.WriteLine(new[] { 1, 2, 3, 4, 5 } is [> 0, > 0, ..]);  // True
Console.WriteLine(new[] { 1, 1 } is [_, _, ..]);  // True
Console.WriteLine(new[] { 0, 1, 2, 3, 4 } is [> 0, > 0, ..]);  // False
Console.WriteLine(new[] { 1 } is [1, 2, ..]);  // False

Console.WriteLine(new[] { 1, 2, 3, 4 } is [.., > 0, > 0]);  // True
Console.WriteLine(new[] { 2, 4 } is [.., > 0, 2, 4]);  // False
Console.WriteLine(new[] { 2, 4 } is [.., 2, 4]);  // True

Console.WriteLine(new[] { 1, 2, 3, 4 } is [>= 0, .., 2 or 4]);  // True
Console.WriteLine(new[] { 1, 0, 0, 1 } is [1, 0, .., 0, 1]);  // True
Console.WriteLine(new[] { 1, 0, 1 } is [1, 0, .., 0, 1]);  // False

záró példa

Példa: Egy alpattern egy szeletmintában ágyazható be:

MatchMessage("aBBA");  // output: Message aBBA matches; inner part is BB.
MatchMessage("apron"); // output: Message apron doesn't match.

void MatchMessage(string message)
{
    var result = message is ['a' or 'A', .. var s, 'a' or 'A']
        ? $"Message {message} matches; inner part is {s}."
        : $"Message {message} doesn't match.";
    Console.WriteLine(result);
}

Validate(new[] { -1, 0, 1 });     // output: not valid
Validate(new[] { -1, 0, 0, 1 });  // output: valid

void Validate(int[] numbers)
{
    var result = numbers is [< 0, .. { Length: 2 or 4 }, > 0]
        ? "valid" : "not valid";
    Console.WriteLine(result);
}

záró példa

11.3 Minta-részsumpció

Egy kapcsolóutasításban (13.8.3. §) hiba, ha egy eset mintáját az előző, nem őrzött esetek halmaza (13.8.3. §) aláveti. Egy kapcsolókifejezésben (12.12.§) hiba, ha egy switch_expression_arm mintáját az előző, nem őrzöttswitch_expression_armmintái alávetik.

Megjegyzés: Ez azt jelenti, hogy a bemeneti értékeket az előző esetek vagy karok egyikével egyeztették volna. végjegyzet A következő szabályok határozzák meg, hogy egy mintakészlet mikor ad részösszeget egy adott mintának:

Egy minta Pakkor egyezik meg egy állandóval K , ha az alábbi feltételek bármelyike fennáll:

  • A minta futtatókörnyezeti viselkedésének specifikációja megegyezik PK.
  • P egy type_pattern a típushoz T , és K nem null , és a futtatókörnyezet típusa K származik TT vagy egy implementált Ttípus.
  • Pegy relational_pattern az "op" operátorral és az állandóvalv, és az "op" K kifejezés v kiértékelése a következő lesztrue: .
  • P egy negated_patternnot P₁ , és P₁ nem egyezik K.
  • P egy conjunctive_patternP₁ and P₂ , és mindkettő P₁ egyezik K , és P₂ megfelelne K.
  • P egy disjunctive_patternP₁ or P₂ , és vagy P₁ egyezik K vagy P₂ egyezik K.
  • Pdiscard_pattern.

A minták Qegy halmaza alávet egy mintát P , ha az alábbi feltételek bármelyike fennáll:

  • P állandó minta, és a készlet Q bármely mintája megegyezik Pa konvertált értékével
  • P egy var minta, és a minták Qkészlete teljes (11.4. §) a minta bemeneti értékének típusához (11.1. §), és vagy a minta bemeneti értéke nem null értékű, vagy egy minta Q egyezik null.
  • P egy típussal T rendelkező deklarációs Qminta, és a minták készlete teljes a típusra T vonatkozóan (11.4. §).
  • P type_pattern a típushoz T , és a minták Q teljes halmaza a típushozTtartozik.
  • P egy relational_pattern az "op" operátorral és az állandó értékkel v, és a bemeneti típus minden olyan értékéhez, amely megfelel az "op" vrelációnak, a készlet Q egy bizonyos mintája megfelelne ennek az értéknek.
  • P a disjunctive_patternP₁ or P₂ és a minták Q alösszegeinek P₁ és Q alösszegeinek halmaza P₂.
  • P egy conjunctive_patternP₁ and P₂ , és legalább az alábbiak egyikét tartalmazza: Q alösszegek P₁vagy Q alösszegek P₂.
  • P egy negated_patternnot P₁ , és Q a bemeneti típus teljes körű , figyelembe véve csak azokat az értékeket, amelyeket P₁nem egyeznek meg.
  • P egy discard_pattern , és a minták Q készlete teljes a minta bemeneti értékének típusára vonatkozóan, és vagy a minta bemeneti értéke nem null értékű, vagy egy minta Q egyezik null.
  • Néhány minta Q egy disjunctive_patternQ₁ or Q₂ , és ha ezt a mintát in értékre Q₁Q cserélné , az olyan készletet eredményezne, amely alösszegeket Peredményezne , vagy ha lecserélné azt Q₂ , akkor ez az alösszegek Phalmazt eredményezne .
  • Egyes minták Qnegated_patternnot Q₁ , és P nem egyeznek meg egyetlen értékkel Q₁ sem.

Példa: A következő kapcsolókifejezésben egyetlen kar sem lesz alárendelve, annak ellenére, hogy az 1., 2. és 3. kar ugyanazzal a mintával rendelkezik:

object x = 10;
bool b = false;
int y = x switch
{
    int i when !b => 0,
    int i when b  => 1,
    int i         => 2,
    _             => 3
};

Az 1. és a 2. kar nem állandó védőburkolatokkal rendelkezik, és így nem őrzetlenek; csak a 3. kar van őrizetlen mintával int i, ami nem alösszegezi a végső _ kart, mert nem egyezik meg egy nem-értékint , például null. záró példa

Az list_patternés a slice_patternalegységeinek szubsumpciós ellenőrzése ugyanúgy működik, mint a (ITuple-ös megfelelő alhálózatokkal rendelkező pozícióminták, valamint a tesztelési hosszhoz szükséges további csomópontok.

A következő kód például hibát okoz, mert mindkét minta ugyanazt a DAG-ot eredményezi:

case [_, .., 1]: // expr.Length is >= 2 && expr[^1] is 1
case [.., _, 1]: // expr.Length is >= 2 && expr[^1] is 1

Ellentétben:

case [_, 1, ..]: // expr.Length is >= 2 && expr[1] is 1
case [.., 1, _]: // expr.Length is >= 2 && expr[^2] is 1

Adott hossz esetén lehetséges, hogy két alpatter ugyanarra az elemre hivatkozik, ebben az esetben az érték tesztelése be lesz szúrva a döntési DAG-ba.

  • A 3-nak például az a helye, [_, >0, ..] or [.., <=0, _]length >= 2 && ([1] > 0 || length == 3 || [^2] <= 0) ahol a 3 hosszúsági érték a másik tesztet jelenti.
  • Ezzel szemben [_, >0, ..] and [.., <=0, _]length >= 2 && [1] > 0 && length != 3 && [^2] <= 0 a 3 hosszúsági érték nem engedélyezi a másik tesztet.

Ennek eredményeképpen hiba fog következni valami hasonló case [.., p]: case [p]: miatt, mert futásidőben ugyanazt az elemet egyezteti a második esetben.

Ha egy szelet allapja megfelel egy listának vagy egy hosszértéknek, az alpattereket úgy kell kezelni, mintha azok a lista közvetlen alpatterei lennének. Például [..[1, 2, 3]] az űrlap [1, 2, 3]egy mintáját alösszegezi.

A használt tagokra a következő feltételezések épülnek:

  • A típust megszámláló tulajdonságot feltételezzük, hogy mindig nem negatív értéket ad vissza, ha és csak akkor, ha a típus indexelhető. A minta { Length: -1 } például soha nem egyezhet meg tömbökben.
  • Az a tag, amely szeletelhetővé teszi a típust, feltételezzük, hogy megfelelően viselkedik; azaz a visszatérési érték soha nem null , és hogy az a tartalmazó lista megfelelő alosztálya.

A mintaegyeztetési művelet viselkedése nem határozható meg, ha a fenti feltételezések közül bármelyik nem áll fenn. [

11.4 Minta teljessége

Informálisan a minták egy típusra vonatkozóan teljes körűek, ha a nulltól eltérő típus minden lehetséges értékére alkalmazható valamilyen minta a készletben. Az alábbi szabályok határozzák meg, hogy egy típus esetében egy mintakészlet mikor teljes:

Egy típusra Q vonatkozó minták teljes körűek, ha az alábbi feltételek bármelyike fennáll:

  1. T egy integrál- vagy számtípus, vagy ezek egyikének null értékű verziója, és a "nem null értékű mögöttes típus" minden lehetséges értékéhez Tbizonyos minta Q megfelelne ennek az értéknek; vagy
  2. Néhány minta Q egy var minta; vagy
  3. A minta Q egy típus D, és van egy identitáskonverzió, egy implicit referenciakonvertálás, vagy egy dobozos átalakítás a típusról TD; vagy
  4. A minta Q egy type_pattern típushoz D, és van egy identitáskonverzió, egy implicit referenciakonvertálás, vagy egy keretkonvertálás a típusról TDaz ; vagy
  5. Néhány minta Q egy discard_pattern; vagy
  6. A minták olyan Qrelational_patternés constant_patterns kombinációját tartalmazzák, amelyek tartományai együttesen lefedik a "nem null értékű mögöttes típus" összes lehetséges értékét T. float A double relációs mintával nem egyezik meg; vagy System.Double.NaN nem felel meg a relációs System.Single.NaN mintának, NaN vagy
  7. Néhány minta Q egy disjunctive_patternP₁ or P₂, és felváltja ezt a mintát mind P₁ a P₂Q hozamok egy készlet, amely kimerítőT; vagy
  8. Néhány minta Q egy negated_patternnot P₁, és a minták Q a nem egyező P₁ értékekkel együtt lefedik a lehetséges értékeket T. A negated_patternnot P₁ önmagában teljes körű, ha P₁ nem felel meg az T; vagy
  9. Néhány minta Qegy conjunctive_patternP₁ and P₂, és a csak P₁ a teljesT értéket tartalmazó készlet teljes, és a csak P₂ a teljes halmazt Ttartalmazza.

Megjegyzés: Ha egy típusminta null értékű típusokat tartalmaz, előfordulhat, hogy a minta teljes a típusra vonatkozóan, de figyelmeztetést is generál, mert a típusminta nem egyezik meg egy null értékkel. végjegyzet

Megjegyzés: A lebegőpontos típusok esetében a minták < 0>= 0 kombinációja nem teljes, mert egyik relációs minta sem egyezik NaN. A teljesség igénye a következő lenne < 0: , >= 0és double.NaN (vagy float.NaN). végjegyzet

Példa:

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;
    }
}

záró példa