Översikt över mönstermatchning

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#. Om du inte har använt programmering tidigare börjar du med självstudierna Komma igång först. Erfarna C#-utvecklare kan använda mönsterreferensen för den fullständiga syntaxen och reglerna.

Kommer du från ett annat språk? C#-mönster har en liknande roll som Javas mönstermatchning och Pythons match-fall. C# använder mönster i is uttryck, switch uttryck och switch uttryck.

Mönstermatchning tillämpar ett mönster på ett uttryck. Ett mönster är ett villkor att testa indatauttrycket mot. Mönsterindata är det uttrycket. C# utvärderar indatauttrycket. resultatet är det utvärderade värdet. Mönstret testar om det värdet har en viss typ, är lika med ett visst värde eller har en viss form. När ett mönster matchar kan koden använda information som lärts av testet, till exempel en mer specifik typ eller ett värde som extraherats från ett objekt.

Du kan använda ett mönster i tre kontexter:

  • Till höger om is operatorn.
  • I en case etikett för en switch -instruktion.
  • I en arm i ett switch uttryck.

Mönster är ofta tydligare än en sekvens med jämförelseinstruktioner eftersom varje gren beskriver de data som den hanterar. Följande metod använder till exempel ett switch uttryck för att välja ett leveransmeddelande:

static string GetDeliveryMessage(Delivery? delivery) =>
    delivery switch
    {
        null => "No delivery was scheduled.",
        ExpressDelivery express => $"Express package {express.TrackingCode}",
        StandardDelivery { Days: <= 2 } => "Standard delivery arriving soon",
        _ => "Standard delivery"
    };

Rekursiva mönster har egna indatauttryck. I StandardDelivery { Days: <= 2 } mottar det yttre mönstret delivery-uttrycket. Det rekursiva <= 2 mönstret tar emot egenskapsuttrycket Days från det matchade StandardDelivery objektet.

Uttrycket före switch är indatauttrycket. Varje rad inuti klammerparenteserna är en växelarm. Mönstret visas före =>och resultatet visas efter det. C# utvärderar indatauttrycket och väljer sedan den första armen, i textordning, vars mönster matchar och vars valfria when skydd är true. Det valfria when skyddet är ytterligare ett booleskt villkor skrivet efter mönstret. Föregående exempel visade följande mönster:

  • null är ett konstant mönster. Den testar om uttrycket delivery utvärderas till null.
  • ExpressDelivery express är ett deklarationsmönster med två delar. ExpressDelivery är delen för typprovning. Den testar om det utvärderade värdet är ett icke-null-objekt vars körningstyp är kompatibel med ExpressDelivery. express är variabelbeteckningen: den deklarerar en variabel med namnet express och tilldelar det matchade ExpressDelivery objektet till den.
  • StandardDelivery { Days: <= 2 } börjar med ett typtest. StandardDelivery testar om det utvärderade värdet är ett icke-null-objekt av den typen. Klamrarna innehåller ett egenskapsmönster. Days namnger egenskapen som ska kontrolleras, så Days egenskapsuttrycket blir indata till det rekursiva mönstret. Delen <= 2 är ett relationsmönster som testar om det utvärderade värdet är mindre än eller lika med 2.
  • _ (understreck) är ignoreringsmönstret. Den matchar varje utvärderat värde, inklusive null. Eftersom tidigare grenar redan hanterar null, expressleveranser och standardleveranser som anländer inom två dagar hanterar den här sista grenen alla återstående värden.

En arm utan when vakt är obevakad. Alla armar i det första exemplet är obevakade. Om en tidigare obevakad arm matchar varje utvärderat värde som en senare arm kan matcha , undersummas den senare armen. Ett undersummat mönster är ett där alla möjliga indatavärden som matchar redan matchades av en tidigare växlingsarm. Det kan aldrig matcha, så kompilatorn rapporterar ett fel. Discard-armen (_) måste komma sist eftersom den matchar alla indatauttryck. En skyddad arm undersummar inte en senare arm enbart baserat på dess mönster eftersom vakten kan vara false.

Ett switch-uttryck är fullständigt när dess grenar hanterar alla möjliga indata. Det första exemplet är uttömmande eftersom dess sista kasserade arm hanterar allt som de tidigare armarna inte matchar. Kompilatorn varnar när den identifierar ett potentiellt indatavärde som ingen arm hanterar. Kompilatorn kan inte bevisa fullständighet för varje kombination av mönster, men den här diagnostiken hjälper dig att skriva rätt mönstermatchningskod. Detaljerade regler för matchning, undersummor och fullständighet finns i mönsterreferensen.

Testa ett villkor med is

Använd operatorn is när du behöver ett booleskt test. Följande kod utvärderar delivery uttrycket och tillämpar deklarationsmönstret ExpressDelivery express. Typdelen matchar när det utvärderade värdet inte är null och dess körningstyp är kompatibel med ExpressDelivery. När mönstret matchar deklarerar dess variabelnamn express:

static void PrintTrackingCode(Delivery delivery)
{
    if (delivery is ExpressDelivery express)
    {
        Console.WriteLine($"Track express package {express.TrackingCode}");
    }
}

Kompilatorn spårar om en lokal variabel har tilldelats innan koden läser den. Den här spårningen kallas för bestämd tilldelning. I blocket if kan villkoret bara vara true när mönstret tilldelade det matchande objektet till express. Kompilatorn vet därför att express definitivt är tilldelad där. Koden kan använda dess egenskap på ett TrackingCode säkert sätt. Du behöver ingen separat rollbesättning. Om du bara behöver typtestet och inte behöver deklarera en variabel använder du ett typmönster, till exempel delivery is ExpressDelivery.

Använd is null eller is not null för null-kontroller. Dessa mönster anropar inte en användardefinierad == operator eller != operator.

static void PrintPackageStatus(Delivery? delivery)
{
    if (delivery is null)
    {
        Console.WriteLine("No package is available.");
    }
    else
    {
        Console.WriteLine("A package is ready to track.");
    }
}

Mer vägledning om null-säkerhet finns i nullbara referenstyper.

Välj mellan en sats och ett uttryck

Mönster fungerar med båda formerna av switch:

  • Använd en switch instruktion när varje matchning ska köra en eller flera instruktioner.
  • Använd ett switch uttryck när varje matchning ska generera ett värde.

Följande switch-instruktion rapporterar en leveransuppdatering. Express-delivery-grenen skriver två meddelanden, så en instruktion passar naturligt:

static void PrintDeliveryUpdate(Delivery? delivery)
{
    switch (delivery)
    {
        case null:
            Console.WriteLine("No delivery was scheduled.");
            break;
        case ExpressDelivery express:
            Console.WriteLine($"Express delivery {express.TrackingCode} is ready.");
            Console.WriteLine("Notify the priority desk.");
            break;
        case StandardDelivery standard:
            Console.WriteLine($"Standard delivery arrives in {standard.Days} days.");
            break;
        default:
            Console.WriteLine("Another delivery type is scheduled.");
            break;
    }
}

Varje case tillämpar ett mönster på uttrycket delivery. Matchningsavsnittet kan köra valfritt antal instruktioner innan break växeln avslutas. Avsnittet default hanterar allt som de tidigare fallen inte matchar.

Följande växeluttryck ersätter en if / else if kedja som tilldelar ett resultat:

static string GetStatusMessage(StandardDelivery delivery) =>
    delivery.Days switch
    {
        0 => "Delivered today",
        1 => "Arriving tomorrow",
        <= 3 => "Arriving soon",
        _ => "In transit"
    };

Ett växeluttryck är koncist eftersom varje arm har samma syfte: generera det returnerade värdet. Använd en switch-instruktion när grenar utför åtgärder och använd ett växeluttryck när grenar beräknar ett resultat.

Mönsterkategorier

C# innehåller mönster för vanliga typer av datatester:

Mönsterkategori Vad det testar
Deklaration, konstant och var mönster En körningstyp, ett specifikt konstant värde eller ett värde som du vill samla in
Typmönster En körningstyp utan att deklarera en variabel
Egenskaps- och positionsmönster Egenskaper, fält eller dekonstruerade värden
Relationella och logiska mönster Jämförelser och kombinationer som and, oroch not
Listamönster Värden och form för en lista eller matris
Ignorera mönster och borttagningar Eventuella återstående värden eller ett värde som koden avsiktligt ignorerar

Grundartiklarna som är länkade i tabellen ger en fokuserad täckning av de kategorier som för närvarande dokumenteras i det här avsnittet. Fullständig syntax och exempel för alla mönsterkategorier finns i mönsterreferensen.

Se även