Relations-, logiska och parentesiserade mönster

Tip

Den här artikeln är en del av avsnittet Grunderna för utvecklare som redan känner till minst ett programmeringsspråk och lär sig C#. Börja med mönstermatchningsöversikten om mönster är nya för dig. Fullständiga språkregler finns i relationsmönster och logiska mönster i språkreferensen.

Relations- och logiska mönster beskriver intervall, alternativ och undantag. Följande metod kombinerar dem för att klassificera en temperatur:

static string ClassifyTemperature(int temperature) =>
    temperature switch
    {
        < 0 => "Below freezing",
        >= 18 and <= 24 => "Comfortable",
        (>= 0 and < 10) or > 30 => "Far outside the comfortable range",
        _ => "Cool or warm"
    };

Uttrycket temperature är mönsterindata. C# utvärderar det en gång, och varje växelarm testar det resulterande värdet. Armarna uppvisar följande tester:

  • < 0 testar en gräns.
  • >= 18 and <= 24 testar ett intervall.
  • (>= 0 and < 10) or > 30 testar två alternativa intervall.

Den här artikeln visar både mönster och imperativa villkor så att du kan lära dig varje formulär och jämföra hur de uttrycker samma beslut. Ett enda villkor kan se liknande ut i båda formerna. Mönster kan göra en serie relaterade grenar enklare att läsa genom att hålla valen bredvid deras resultat. Välj det formulär som gör koden enklast att förstå.

Jämföra värden med relationsmönster

Ett relationsmönster jämför dess mönsterindata med en kompileringskonstant med hjälp <av , >, <=eller >=. En kompileringskonstant är ett värde som kompilatorn kan utvärdera när programmet kompileras. Numeriska teckenliteraler och const variabler för kompatibla numeriska typer eller teckentyper är representativa exempel. Vanliga variabler, egenskaper, metodanrop och static readonly fält är inte kompileringskonstanter. I öppningsexemplet testar både >= 18 och <= 24 samma utvärderade temperature värde.

Samma relationssymbol kan visas i ett vanligt uttryck eller i ett mönster. I följande exempel används båda formerna för en temperatur:

static void ShowExpressionAndPattern(int temperature, int threshold)
{
    bool belowThreshold = temperature < threshold;
    bool belowFreezing = temperature is < 0;

    string description = temperature switch
    {
        < 0 => "Freezing",
        0 => "Freezing point",
        > 0 => "Above freezing"
    };

    Console.WriteLine(
        $"Below threshold: {belowThreshold}; " +
        $"below freezing: {belowFreezing}; {description}");
}

temperature < threshold är ett relationsuttryck. Den utvärderar båda operanderna och skapar en bool. Båda operanderna kan vara ett icke-stant uttryck.

I temperature är temperature is < 0 indatauttrycket för mönstret. C# utvärderar det och relationsmönstret < 0 testar det resulterande värdet. I växlingsarmen < 0 => "Freezing"innehåller uttrycket innan switch indata, så mönstret innehåller bara < 0.

Uttrycket kan jämföras temperature med variabeln threshold. En relationsmönsteropernd måste vara en kompileringskonstant, så använd relationsuttrycket när jämförelsevärdet är en variabel. När jämförelsevärdet är konstant kan båda formulären fungera.

När rätt operande är konstant väljer du främst för läsbarhet. Ett relationsuttryck passar ofta en direkt jämförelse. Ett relationsmönster består av andra mönster och passar naturligt när flera intervall mappas för att växla resultat.

Kombinera villkor med logiska mönster

Logiska mönster kombinerar eller negerar mönster med mönsteroperatorerna and, oroch not:

  • Ett and-mönster matchas när båda de kapslade mönstren matchar.
  • Ett or-mönster matchar när ett av de kapslade mönstren matchar.
  • Ett not mönster lyckas när det kapslade mönstret misslyckas.

I öppningsexemplet används and för att beskriva ett intervall och or för att beskriva alternativ. Ett not mönster kan exkludera ett värde, som i status is not Status.Complete. Följande metoder visar båda formulären så att du kan lära dig deras syntax och jämföra hur de uttrycker samma test:

static bool IsWeekendPattern(DayOfWeek day) =>
    day is DayOfWeek.Saturday or DayOfWeek.Sunday;

static bool IsWeekendImperative(DayOfWeek day) =>
    day == DayOfWeek.Saturday || day == DayOfWeek.Sunday;

Mönsterformuläret använder två konstanta mönster som är kopplade till or. Det imperativa formuläret använder två likhetsuttryck som är kopplade till operatorn ||conditional-OR . Båda formulären är koncisa och tydliga för det här enskilda villkoret. Välj det formulär som passar bäst för den omgivande koden. Mönster klargör ofta flera relaterade val i en switch, som i öppningsexemplet.

Mönsteroperatorer bildar mönster i stället för booleska uttryck: and motsvarar mönsterkjunktion, or mönsteralternativ och not mönsterförnekelse. Booleska uttryck använder &&, ||och !. Välj or när flera mönsteralternativ har samma resultat. Välj not när du uttrycker det exkluderade mönstret är tydligare än att visa varje godkänt värde.

Gruppera mönster med parenteser

Ett parenteserat mönster använder parenteser för att visa eller ändra hur kapslade mönster grupperas. Bindning avgör vilka mönsteroperander en operator grupperar tillsammans, på samma sätt som implicit gruppering när du inte använder parenteser. C# anger följande bindningsordning:

  1. not
  2. and
  3. or

I följande test godkänns prioriteterna 1 till 3 eller den särskilda prioriteten 9:

static bool IsAcceptedPriority(int priority) =>
    priority is (>= 1 and <= 3) or 9;

Kompilatorn grupperar and före or. Parenteserna gör den avsedda grupperingen explicit och de två alternativen är lätta att se: intervallet från 1 till 3 eller 9. För läsbarhet använder du parenteser när ett mönster blandas and och or, eller när not det gäller ett sammansatt mönster. Parenteser kan också ändra standardgruppering, som i not (>= 1 and <= 3).

Körningskontrollordningen för kapslade mönster är ospecificerad och mönsteroperatorer följer mönstermatchningsregler i stället för kortslutna booleska regler. Skriv kapslade mönster så att resultatet är oberoende av kontrollordningen.

Använd en when-vakt för ett separat villkor

Logiska mönster fungerar bäst när kapslade mönster beskriver själva indatavärdet. Ett when skydd är ytterligare ett booleskt villkor på en case etikett eller växlingsarm. Använd ett skydd när beslutet också beror på information som är separat från mönsterindata.

Följande varning beror på temperaturen och ett separat isOutdoors värde:

static string GetHeatWarning(int temperature, bool isOutdoors) =>
    temperature switch
    {
        > 35 when isOutdoors => "High heat outdoors",
        > 35 => "High heat",
        _ => "No heat warning"
    };

Relationsmönstret > 35 beskriver temperature indata. Vakten when isOutdoors kontrollerar ett separat värde. Ett skydd är också att föredra när villkoret behöver ett metodanrop eller ett booleskt uttryck som mönstersyntaxen inte uttrycker tydligt.

Använd relations- och logiska mönster när de gör indatas tillåtna former eller värden lättare att se, särskilt över flera växlingsarmar. Använd ett vanligt booleskt uttryck när det anger ett direkt villkor enklare. Använd ett when skydd när ett växelval beror på ett separat värde eller på ett villkor som uttrycks bättre som ett booleskt uttryck.

Se även