11 Patronen en patroonkoppeling

11.1 Algemeen

Een patroon is een syntactische vorm die kan worden gebruikt met de is operator (§12.15.12), in een switch_statement (§13.8.3) en in een switch_expression (§12.12) om de vorm van gegevens uit te drukken waarmee binnenkomende gegevens moeten worden vergeleken. Patronen kunnen recursief zijn, zodat delen van de gegevens kunnen worden vergeleken met subpatronen.

Een patroon wordt getest op basis van een waarde in een aantal contexten:

  • In een switch-instructie wordt het patroon van een caselabel getest op basis van de expressie van de switch-instructie .
  • In een is-pattern-operator wordt het patroon aan de rechterkant getest op de expressie aan de linkerkant.
  • In een switchexpressie wordt het patroon van een switch_expression_arm getest op basis van de expressie aan de linkerkant van de switch-expressie.
  • In geneste contexten wordt het subpatroon getest op waarden die zijn opgehaald uit eigenschappen, velden of geïndexeerd van andere invoerwaarden, afhankelijk van het patroonformulier.

De waarde waarmee een patroon wordt getest, wordt de invoerwaarde van het patroon genoemd.

11.2 Patroonformulieren

11.2.1 Algemeen

Een patroon kan een van de volgende vormen hebben:

pattern
    : logical_pattern
    ;

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

parenthesized_pattern
    : '(' pattern ')'
    ;

Met '(' pattern ')' de productie kan een patroon tussen haakjes worden geplaatst om de evaluatievolgorde af te dwingen tussen patronen gecombineerd met behulp van een van de logical_patterns.

Sommige patronenkunnen resulteren in de declaratie van een lokale variabele.

Elk patroonformulier definieert de set typen voor invoerwaarden waarop het patroon kan worden toegepast. Een patroon P is van toepassing op een type T als T het een van de typen is waarvan de waarden overeenkomen met het patroon. Het is een compilatiefout als een patroon P wordt weergegeven in een programma dat overeenkomt met een patrooninvoerwaarde (§11.1) van het type T als P dit niet van toepassing is op T.

Voorbeeld: In het volgende voorbeeld wordt een compilatiefout gegenereerd omdat het type v compileertijd is TextReader. Een variabele van het type TextReader kan nooit een waarde hebben die compatibel is met 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
}

Het volgende genereert echter geen compilatietijdfout omdat het type v compileertijd is object. Een variabele van het type object kan een waarde hebben die compatibel is met string:

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

eindvoorbeeld

Elk patroonformulier definieert de set waarden waarvoor het patroon overeenkomt met de waarde tijdens runtime.

De volgorde van evaluatie van bewerkingen en bijwerkingen tijdens patroonkoppeling (aanroepen naar Deconstruct, eigenschapstoegang en aanroepen van methoden in System.ITuple) is niet opgegeven.

11.2.2 Declaratiepatroon

Een declaration_pattern wordt gebruikt om te testen of een waarde een bepaald type heeft en, als de test slaagt, om desgewenst de waarde in een variabele van dat type op te geven.

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

Een simple_designation met het token _ wordt beschouwd als een discard_designation in plaats van een single_variable_designation.

Het runtimetype van de waarde wordt getest op basis van het type in het patroon met behulp van dezelfde regels die zijn opgegeven in de operator is-type (§12.15.12.1). Als de test slaagt, komt het patroon overeen met die waarde. Het is een compilatiefout als het type een type nullable waarde is (§8.3.12) of een nullable verwijzingstype (§8.9.3). Dit patroonformulier komt nooit overeen met een null waarde.

Opmerking: de is-type-expressie e is T en het declaratiepatroon e is T _ zijn equivalent wanneer T het geen null-type is. eindnotitie

Gezien een patrooninvoerwaarde (§11.1) e, als de simple_designationis discard_designation, wordt een verwijdering aangegeven (§9.2.9.2) en de waarde van e is niet gebonden aan iets. (Hoewel een gedeclareerde variabele met de naam _ op dat moment mogelijk binnen het bereik valt, wordt die benoemde variabele niet gezien in deze context.) Als de simple_designationsingle_variable_designation is, wordt een lokale variabele (§9.2.9) van het opgegeven type met de opgegeven id geïntroduceerd. Aan die lokale variabele wordt de waarde van de invoerwaarde van het patroon toegewezen wanneer het patroon overeenkomt met de waarde.

Bepaalde combinaties van het statische type van de patrooninvoerwaarde en het opgegeven type worden beschouwd als niet compatibel en resulteren in een compilatiefout. Een waarde van het statische type E wordt gezegd dat het patroon compatibel is met het type T als er een identiteitsconversie bestaat, een impliciete of expliciete verwijzingsconversie, een boksconversie, een conversie van het uitboxen, of een impliciete of expliciete conversie van E waardetype voor null naar T, of als E het een T open type is (§8.4.3). Een declaratiepatroon met de naam van een type T is van toepassing op elk type E waarvoor E een patroon compatibel is met T.

Opmerking: de ondersteuning voor open typen kan het handigst zijn bij het controleren van typen die struct- of klassetypen kunnen zijn, en boksen moet worden vermeden. eindnotitie

Voorbeeld: Het declaratiepatroon is handig voor het uitvoeren van runtime-typetests van referentietypen en vervangt het idioom

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

met de iets beknopter

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

eindvoorbeeld

Voorbeeld: Het declaratiepatroon kan worden gebruikt om waarden van null-typen te testen: een waarde van het type Nullable<T> (of een vakken T) komt overeen met een typepatroon T2 id als de waarde niet null is en T2 of Teen basistype of interface van T. Bijvoorbeeld in het codefragment

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

De voorwaarde van de if instructie is true tijdens runtime en de variabele v bevat de waarde 3 van het type int in het blok. Nadat het blok is bereikt, is de variabele v binnen het bereik, maar niet zeker toegewezen. eindvoorbeeld

11.2.3 Constant patroon

Een constant_pattern wordt gebruikt om de waarde van een patrooninvoerwaarde (§11.1) te testen op basis van de opgegeven constante waarde.

constant_pattern
    : constant_expression
    ;

Een constant patroon P is van toepassing op een type T als er een impliciete conversie van de constante expressie van P het type Tis.

Voor een constant patroon Pis de geconverteerde waarde

  • als het type van de patrooninvoerwaarde een integraal type of een opsommingstype is, wordt de constante waarde van het patroon geconverteerd naar dat type; anders
  • als het type van de invoerwaarde van het patroon de null-versie van een integraal type of een enumtype is, wordt de constante waarde van het patroon geconverteerd naar het onderliggende type; anders
  • de waarde van de constante waarde van het patroon.

Gegeven een patrooninvoerwaarde e en een constant patroon P met geconverteerde waarde v,

  • als e een integraal type of opsommingstype of een null-vorm van een van deze heeft en v een integraal type heeft, komt het patroon P overeen met de waarde e als het resultaat van de expressie e == v istrue; anders
  • het patroon Povereenkomt met de waarde e als object.Equals(e, v) deze retourneert true.

Voorbeeld: De switch instructie in de volgende methode maakt gebruik van vijf constante patronen in de caselabels.

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

eindvoorbeeld

11.2.4 Var pattern

Een var_patternkomt overeen met elke waarde. Dat wil gezegd, een patroonkoppelingsbewerking met een var_pattern altijd slaagt.

Een var_pattern is van toepassing op elk type.

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

Uitgaande van een patrooninvoerwaarde (§11.1) e, als aanduidingis discard_designation, wordt een verwijdering aangegeven (§9.2.9.2) en de waarde van e is niet gebonden aan iets. (Hoewel op dat moment een gedeclareerde variabele met die naam mogelijk binnen het bereik valt, wordt die benoemde variabele niet gezien in deze context.) Als de aanduidingsingle_variable_designation is, is de waarde van e tijdens runtime gebonden aan een nieuw geïntroduceerde lokale variabele (§9.2.9) van die naam waarvan het type het statische type e is en de invoerwaarde van het patroon wordt toegewezen aan die lokale variabele.

Dit is een fout als de naam var zou binden aan een type waarbij een var_pattern wordt gebruikt.

Als aanduiding een tuple_designation is, is het patroon gelijk aan een positional_pattern (§11.2.5) van de (var, ... ) indien de aanduidingenin de tuple_designation worden gevonden. Het patroon var (x, (y, z)) is bijvoorbeeld gelijk aan (var x, (var y, var z)).

11.2.5 Positioneel patroon

Een positional_pattern controleert of de invoerwaarde niet nullis, roept een geschikte Deconstruct methode aan (§12.7) en voert verdere patroonkoppelingen uit op de resulterende waarden. Het ondersteunt ook een tuple-achtige patroonsyntaxis (zonder het type dat wordt opgegeven) wanneer het type van de invoerwaarde hetzelfde is als het type dat Deconstructhet type invoerwaarde bevat, of als het type van de invoerwaarde een tupletype is, of als het type van de invoerwaarde is object of System.ITuple als het runtimetype van de expressie wordt System.ITuplegeïmplementeerd.

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

Gezien een overeenkomst van een invoerwaarde met desubpatronen( van het patroontype), wordt een methode geselecteerd door in het type te zoeken naar toegankelijke declaraties van Deconstruct en er een te selecteren met dezelfde regels als voor de deconstructiedeclaratie. Het is een fout als een positional_pattern het type weglaat, één subpatroon zonder id heeft, geen property_subpattern heeft en geen simple_designation heeft. Dit onderscheidt zich tussen een constant_pattern die haakjes en een positional_pattern is. Als u de waarden wilt extraheren die overeenkomen met de patronen in de lijst,

  • Als u het type invoerexpressie weglaat en het type van de invoerexpressie een tupletype is, moet het aantal subpatronen gelijk zijn aan de kardinaliteit van de tuple. Elk tuple-element wordt vergeleken met het bijbehorende subpatroon en de overeenkomst slaagt als dit allemaal lukt. Als een subpatroon een id heeft, noemt die een tuple-element op de bijbehorende positie in het tupletype.
  • Als er anders een geschikt Deconstruct lid van het type bestaat, is het een compilatiefout als het type invoerwaarde niet compatibel is met het type. Tijdens runtime wordt de invoerwaarde getest op basis van het type. Als dit mislukt, mislukt de positionele patroonovereenkomst. Als dit lukt, wordt de invoerwaarde geconverteerd naar dit type en Deconstruct wordt deze aangeroepen met nieuwe door compiler gegenereerde variabelen om de uitvoerparameters te ontvangen. Elke waarde die is ontvangen, wordt vergeleken met het bijbehorende subpatroon en de overeenkomst slaagt als al deze waarden slagen. Als een subpatroon een id heeft, wordt dan een parameter op de bijbehorende positie van Deconstruct.
  • Als het type wordt weggelaten en de invoerwaarde van het type object is of een type waarnaar kan worden geconverteerd System.ITuple door een impliciete verwijzingsconversie en er geen id wordt weergegeven onder de subpatronen, wordt de overeenkomst gebruikt System.ITuple.
  • Anders is het patroon een compilatiefout.

De volgorde waarin subpatronen tijdens runtime worden vergeleken, is niet opgegeven en een mislukte overeenkomst probeert mogelijk niet alle submappen te vinden.

Voorbeeld: Hier wordt een expressieresultaat gedeconstrueerd en worden de resulterende waarden vergeleken met de bijbehorende geneste patronen:

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

eindvoorbeeld

Voorbeeld: De namen van tuple-elementen en Deconstruct-parameters kunnen als volgt worden gebruikt in een positioneel patroon:

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

De geproduceerde uitvoer is

Sum of [10 20 30] is 60

eindvoorbeeld

11.2.6 Eigenschapspatroon

Een property_pattern controleert of de invoerwaarde niet nullis en komt recursief overeen met waarden die zijn geëxtraheerd door het gebruik van toegankelijke eigenschappen of velden.

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

Dit is een fout als een subpatroon van een property_pattern geen id bevat.

Het is een compilatiefout als het type een type nullable waarde is (§8.3.12) of een nullable verwijzingstype (§8.9.3).

Opmerking: een null-controlepatroon valt buiten een triviaal eigenschapspatroon. Als u wilt controleren of de tekenreeks s niet null is, kunt u een van de volgende formulieren schrijven:

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

eindnotitie

Gezien een overeenkomst van een expressie e met desubpatronen{van het patroontype}, is het een compilatiefout als de expressie e niet compatibel is met het type T dat door het type is aangewezen. Als het type afwezig is, wordt ervan uitgegaan dat het type het statische type e is. Elk van de id's die aan de linkerkant van de submappen worden weergegeven, wijst een toegankelijk leesbare eigenschap of veld van T aan. Als de simple_designation van de property_pattern aanwezig is, declareert deze een patroonvariabele van het type T.

Tijdens runtime wordt de expressie getest op T. Als dit mislukt, mislukt de overeenkomst van het eigenschappenpatroon en is falsehet resultaat. Als dit lukt, wordt elk property_subpattern veld of eigenschap gelezen en wordt de waarde ervan vergeleken met het bijbehorende patroon. Het resultaat van de hele overeenkomst is false alleen als het resultaat van een van deze is false. De volgorde waarin subpatronen worden vergeleken, is niet opgegeven en een mislukte overeenkomst test mogelijk niet alle subpatronen tijdens runtime. Als de overeenkomst slaagt en de simple_designation van de property_pattern een single_variable_designation is, wordt aan de gedeclareerde variabele de overeenkomende waarde toegewezen.

De property_pattern kan worden gebruikt voor patroonovereenkomsten met anonieme typen.

Voorbeeld:

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

eindvoorbeeld

Voorbeeld: Een controle van een runtimetype en een variabeledeclaratie kunnen als volgt worden toegevoegd aan een eigenschapspatroon:

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

De geproduceerde uitvoer is

Hello
Hi!
12345
abc

eindvoorbeeld

11.2.7 Patroon negeren

Elke expressie komt overeen met het verwijderingspatroon, wat resulteert in de waarde van de expressie die wordt verwijderd.

discard_pattern
    : '_'
    ;

Het is een compilatiefout voor het gebruik van een verwijderingspatroon in een relational_expression van het formulier relational_expressionispatroon of als het patroon van een switch_label.

Opmerking: In dergelijke gevallen gebruikt u een var_pattern met een verwijdering var _om een expressie te vinden. eindnotitie

Voorbeeld:

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

De geproduceerde uitvoer is

5.0
0.0
0.0

Hier wordt een verwijderingspatroon gebruikt om te verwerken null en alle gehele getallen die niet het bijbehorende lid van de DayOfWeek opsomming hebben. Dit garandeert dat de switch expressie alle mogelijke invoerwaarden verwerkt. eindvoorbeeld

11.2.8 Type patroon

Er wordt een type_pattern gebruikt om te testen of de invoerwaarde van het patroon (§11.1) een bepaald type heeft.

type_pattern
    : type
    ;

Een typepatroon dat een type T noemt, is van toepassing op elk type E waarvan Ehet patroon compatibel is met T (§11.2.2).

Het runtimetype van de waarde wordt getest op basis van het type met dezelfde regels die zijn opgegeven in de operator is-type (§12.15.12.1). Als de test slaagt, komt het patroon overeen met die waarde. Het is een compilatietijdfout als het type een null-type is. Dit patroonformulier komt nooit overeen met een null waarde.

11.2.9 Relationeel patroon

Een relational_pattern wordt gebruikt om de patrooninvoerwaarde (§11.1) relationeel te testen op basis van een constante waarde.

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

De relational_expression in een relational_pattern is vereist om een constante waarde te evalueren.

Relationele patronen ondersteunen de relationele operators<, <=en >>= op alle ingebouwde typen die ondersteuning bieden voor dergelijke binaire relationele operators met hetzelfde type: sbyte, byteshort, , , longushortuintint, ulongcharfloat, double, decimal, , nintenums. nuint

Een relational_pattern is van toepassing op een type T als er een geschikte ingebouwde binaire relationele operator is gedefinieerd met beide operanden van het type T, of als er een expliciete null-conversie of het ongedaan maken van conversie bestaat van T naar het type van de constante expressie.

Dit is een compilatiefout als de expressie resulteert in double.NaN, float.NaNof een null-constante.

Wanneer de invoerwaarde een type heeft waarvoor een geschikte ingebouwde binaire relationele operator is gedefinieerd, wordt de evaluatie van die operator beschouwd als de betekenis van het relationele patroon. Anders wordt de invoerwaarde geconverteerd naar het type constante expressie met behulp van een expliciete null-conversie of het ongedaan maken van de conversie. Het is een compilatiefout als er geen conversie bestaat. Het patroon wordt beschouwd als niet overeenkomen als de conversie mislukt. Als de conversie slaagt, is het resultaat van de patroonkoppelingsbewerking het resultaat van het evalueren van de expressie e «op» v waarin e de geconverteerde invoer ,op» de relationele operator is en v de constante expressie.

Voorbeeld:

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

De geproduceerde uitvoer is

Too high
Unknown
Acceptable

eindvoorbeeld

11.2.10 Logisch patroon

Een logical_pattern wordt gebruikt om het resultaat van een patroonovereenkomst te vernieren of om de resultaten van meerdere patroonovereenkomsten te combineren met behulp van combinatie (and) of disjunction (or).

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, anden or worden gezamenlijk patroonoperators genoemd.

Een negated_pattern komt overeen als het patroon dat wordt genegeerd, niet overeenkomt en omgekeerd. Voor een conjunctive_pattern moeten beide patronen overeenkomen. Voor een disjunctive_pattern moet een van beide patronen overeenkomen. In tegenstelling tot de tegenhangers van de taaloperator en && , and en ||or zijn geen kortsluitingsoperatoren.

Het is een compilatietijdfout voor een patroonvariabele die moet worden gedeclareerd onder een not of or patroonoperator.

Opmerking: Omdat noch notor een definitieve toewijzing voor een patroonvariabele kan produceren, is het een fout om er een te declareren in deze posities. eindnotitie

In een conjunctive_pattern wordt het invoertype van het tweede patroon beperkt door het type beperkende vereisten van het eerste patroon van het and. Het beperkte type van een patroon P wordt als volgt gedefinieerd:

  • Als P dit een typepatroon is, is het beperkte type het type van het type van het type patroon.
  • P Als dit een declaratiepatroon is, is het beperkte type het type van het type van het declaratiepatroon.
  • P Als dit een recursief patroon is dat een expliciet type geeft, is het beperkte type dat type.
  • Als er anders P wordt gematcht via de regels voor ITuple in een positional_pattern (§11.2.5), is het beperkte type het type System.ITuple.
  • P Als dit een constant patroon is waarbij de constante niet de null-constante is en waarbij de expressie geen constante expressieconversie naar het invoertype heeft, is het beperkte type het type van de constante.
  • Als dit P een relationeel patroon is waarbij de constante expressie geen constante expressieconversie heeft naar het invoertype, is het beperkte type het type van de constante.
  • P Als dit een or patroon is, is het beperkte type het gemalen type van het beperkte type van de subpatronen als er een dergelijk gemeenschappelijk type bestaat. Voor dit doel beschouwt het algemene type algoritme alleen identiteiten, boksen en impliciete verwijzingsconversies, en wordt rekening met alle subpatronen van een reeks or patronen (waarbij haakjes worden genegeerd).
  • P Als dit een and patroon is, is het beperkte type het beperkte type van het juiste patroon. Bovendien is het beperkte type van het linkerpatroon het invoertype van het rechterpatroon.
  • Anders is Phet beperkte typeP van het invoertype.

Opmerking: Zoals aangegeven door de grammatica, not heeft voorrang op and, die voorrang heeft op or. Dit kan expliciet worden aangegeven of overschreven met haakjes. eindnotitie

Wanneer een patroon aan de rechterkant van ishet patroon wordt weergegeven, wordt de omvang van het patroon bepaald door de grammatica. Hierdoor binden de patroonoperatoren anden ornot binnen het patroon nauwer dan de logische operatoren &&||en ! buiten het patroon.

Voorbeeld:

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

De geproduceerde uitvoer is

High
Too low
Acceptable

eindvoorbeeld

Voorbeeld:

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

De geproduceerde uitvoer is

winter
autumn
spring

eindvoorbeeld

Voorbeeld:

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

De geproduceerde uitvoer is

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

eindvoorbeeld

11.3 Patroonsubsumption

In een switch-instructie is het een fout als het patroon van een case wordt aangevuld met de voorgaande reeks niet-bewaakte zaken (§13.8.3). Informeel betekent dit dat elke invoerwaarde zou overeenkomen met een van de vorige gevallen. De volgende regels definiëren wanneer een set patronen een bepaald patroon samenvat:

Een patroon Pkomt overeen met een constante K als een van de volgende voorwaarden geldt:

  • de specificatie voor het runtimegedrag van dat patroon is dat P overeenkomt met K.
  • P is een type_pattern voor het type T en K niet null en het runtimetype K is T of een type dat is afgeleid van T of een type dat wordt geïmplementeerd T.
  • P is een relational_pattern met operator «op» en constante v, en de expressie K «op» v zou resulteren in true.
  • P is een negated_patternnot P₁ en P₁ komt niet overeen K.
  • P is een conjunctive_patternP₁ and P₂ en beide P₁ zouden overeenkomen K en P₂ zouden overeenkomen K.
  • P is een disjunctive_patternP₁ or P₂ en komt P₁ overeen K of P₂ komt overeen K.
  • P is een discard_pattern.

Een set patronen Qbevat een patroon P als een van de volgende voorwaarden geldt:

  • P is een constant patroon en een van de patronen in de set Q komt overeen met Pde geconverteerde waarde
  • P is een var-patroon en de set patronen Q is volledig (§11.4) voor het type van de patrooninvoerwaarde (§11.1), en de patrooninvoerwaarde is niet van een null-type of een bepaald patroon komt Q overeen null.
  • P is een declaratiepatroon met type T en de set patronen Q is volledig voor het type T (§11.4).
  • P is een type_pattern voor het type T en de set patronen Q is volledig voor het type T.
  • P is een relational_pattern met operator «op» en constante waarde v, en voor elke waarde van het invoertype dat voldoet aan de relatie «op» v, komt een patroon in de set Q overeen met die waarde.
  • Pis een disjunctive_patternP₁ or P₂ en de set patronen Q subsumen en Q subsumen P₁P₂.
  • P is een conjunctive_patternP₁ and P₂ en ten minste één van de volgende bewaringen: Q subsumen P₁, of Q subsumen P₂.
  • P is een negated_patternnot P₁ en Q is volledig voor het invoertype, waarbij alleen de waarden worden overwogen die niet overeenkomen met P₁.
  • P is een discard_pattern en de set patronen Q is volledig voor het type patrooninvoerwaarde en de invoerwaarde van het patroon is niet van een null-type of een bepaald patroon komt Q overeen null.
  • Een bepaald patroon in Q is een disjunctive_patternQ₁ or Q₂ en als u dat patroon Q₁ vervangt door in Q , zou dit een set opleveren die subsumen Pbevat of door deze Q₂ te vervangen door een set die subsumen Pzou opleveren.
  • Een patroon in Q is een negated_patternnot Q₁ en P komt niet overeen met een waarde die Q₁ zou overeenkomen.

11.4 Patroon volledigheid

Informeel is een set patronen volledig voor een type als, voor elke mogelijke waarde van dat type anders dan null, een bepaald patroon in de set van toepassing is. De volgende regels definiëren wanneer een set patronen volledig is voor een type:

Een reeks patronen Q is volledig voor een type T als een van de volgende voorwaarden geldt:

  1. T is een integraal of opsommingstype, of een null-versie van een van deze, en voor elke mogelijke waarde van Thet niet-nulle onderliggende type komt een bepaald patroon Q overeen met die waarde; of
  2. Een bepaald patroon is Q een var-patroon; of
  3. Een bepaald patroon is Q een declaratiepatroon voor het type Den er is een identiteitsconversie, een impliciete verwijzingsconversie of een boksconversie van T naar D; of
  4. Een bepaald patroon Q is een type_pattern voor het type D, en er is een identiteitsconversie, een impliciete verwijzingsconversie of een boksconversie van T naar D; of
  5. Een bepaald patroon Q is een discard_pattern; of
  6. De patronen in Q omvatten een combinatie van relational_patterns en constant_patternwaarvan de bereiken gezamenlijk elke mogelijke waarde van Thet niet-nullable onderliggende type omvatten. Voor float en double typen omvat System.Double.NaNSystem.Single.NaN dit respectievelijk, omdat NaN dit niet overeenkomt met een relationeel patroon; of
  7. Een bepaald patroon is Q een disjunctive_patternP₁ or P₂ en het vervangen van dat patroon door zowel P₁ als P₂ in Q een set die volledig is voor T; of
  8. Een bepaald patroon in Q is een negated_patternnot P₁, en de patronen in Q combinatie met de waarden die niet overeenkomen met P₁ elke mogelijke waarde van T. Een negated_patternnot P₁ is op zichzelf uitputtend wanneer P₁ geen mogelijke waarde van T; of
  9. Een bepaald patroon is Q een conjunctive_patternP₁ and P₂ en de set die alleen P₁uitputtelijkT is en de set die alleen P₂uitputtelijk is voor T.

Opmerking: Wanneer een typepatroon null-typen bevat, kan het patroon volledig zijn voor het type, maar nog steeds een waarschuwing genereren omdat het typepatroon niet overeenkomt met een null waarde. eindnotitie

Opmerking: Voor typen drijvende komma's is de combinatie van patronen < 0niet>= 0 volledig, omdat geen van beide relationele patronen overeenkomtNaN. Een juiste volledige set zou zijn < 0, >= 0en double.NaN (of float.NaN). eindnotitie

Voorbeeld:

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

eindvoorbeeld