Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
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 egenskapsmönster och positionsmönster i språkreferensen.
Både egenskaps- och positionsmönster testar delar av ett värde. Skillnaden är hur de identifierar dessa delar:
- Ett egenskapsmönster namnger de egenskaper eller fält som ska testas.
- Ett positionsmönster identifierar värden efter deras ordning.
En dekonstruktion exponerar en ordnad uppsättning komponentvärden. En tupel har redan en ordning på elementen; se dekonstruera tupler. För en annan typ definierar en Deconstruct metod vilka komponentvärden som exponeras och deras ordning.
Jämför namn och positioner
Följande egenskapsmönster testar två namngivna egenskaper för en väderavläsning, med temperaturvärden i grader Celsius:
static bool IsHotAndHumid(WeatherReading reading) =>
reading is { TemperatureC: > 30, HumidityPercent: > 70 };
sealed record WeatherReading(int TemperatureC, int HumidityPercent);
Följande positionsmönster testar ett signalvärde följt av ett booleskt värde:
static string GetCrossingInstruction(
PedestrianSignal signal, bool crossingIsClear) =>
(signal, crossingIsClear) switch
{
(PedestrianSignal.Walk, true) => "Cross now",
(PedestrianSignal.Walk, false) => "Wait for the crossing to clear",
_ => "Wait for the walk signal"
};
enum PedestrianSignal
{
Stop,
Walk
}
Egenskapsmönstret identifierar dess indata med namnen TemperatureC och HumidityPercent. Korsningskoden skapar en tupel från de separata värdena signal och crossingIsClear. Tuppelns mönster identifierar sedan dessa värden efter ordning: signal första och crossingIsClear andra. Ett positionellt mönster passar starkt eftersom den här nyskapade tuppeln bara har två värden, och deras ordning har en tydlig betydelse i övergångsbeslutet.
Välj ett egenskapsmönster när medlemsnamn hjälper till att förklara testet. Egenskapsmönster är vanligtvis tydligare för klasser, structs och poster. Välj ett positionsmönster när ordningen redan ger värdena en uppenbar betydelse. Positionsmönster är mest användbara med tupplar, som kombinerar flera relaterade värden till ett värde med en fast ordning.
Följ kapslade indata i rekursiva mönster
Egenskaps- och positionsmönster är rekursiva mönster: De tillämpar ett annat mönster på varje egenskap, fält eller position som de väljer. Det valda värdet blir indata till det kapslade mönstret.
I reading är uttrycket IsHotAndHumid indata till egenskapsmönstret. C# utvärderar uttrycket innan matchning. Mönstret hämtar två värden från det resulterande objektet:
- Relationsmönstret
> 30testar värdet förTemperatureC. - Relationsmönstret
> 70testar värdet förHumidityPercent.
Ett yttre typtest är valfritt och rekursiva mönstersatser kan vara tomma. Det tomma egenskapsmönstret { } matchar till exempel alla utvärderade värden som inte är null.
Egenskaps- och positionsmönster matchar endast utvärderade värden som inte är null. När null är en del av indatadomänen väljer du ett rekursivt mönster som söker efter ett värde som inte är null först:
static string DescribeNullableInput(object? value)
{
if (value is not { } nonNullValue)
{
return "No value";
}
return nonNullValue switch
{
DateTime => "Date",
string => "Text",
_ => "Another type"
};
}
Indatauttrycket är value. C# utvärderar det och { } egenskapsmönstret testar det resulterande värdet för icke-null innan det tilldelas till nonNullValue. Följande switchuttryck kan sedan testa flera möjliga körningstyper. Dess DateTime mönster och string typmönster har ingen beteckning eftersom metoden bara behöver identifiera varje typ, inte avbilda dess värde.
När rekursiva mönstersatser innehåller kapslade mönster blir varje vald egenskap, fält eller position indata till det kapslade mönstret.
Du kan lägga till ett typtest före klammerparenteserna när indatauttrycket kan skapa olika typer. Du kan också använda en medlemssökväg för att testa en kapslad egenskap:
static string DescribeDate(object? value) =>
value switch
{
DateTime { Date.DayOfWeek:
DayOfWeek.Saturday or DayOfWeek.Sunday } => "Weekend date",
DateTime => "Weekday date",
null => "No date",
_ => "Not a date"
};
value är indatauttrycket. C# utvärderar först det och testar om det resulterande värdet är en DateTime. Egenskapsvärdet Date blir sedan indata för medlemsåtkomsten DayOfWeek . Slutligen utgör värdet DayOfWeek indata till det logiska mönstret som testar två konstanter. Matchning lyckas när det externa värdet har den angivna typen och varje objekt som behövs i medlemssökvägen är icke-null.
Jämför mönster med förgreningsuttryck
Den tidigare DescribeDate metoden uttrycker fyra resultat som mönster:
static string DescribeDate(object? value) =>
value switch
{
DateTime { Date.DayOfWeek:
DayOfWeek.Saturday or DayOfWeek.Sunday } => "Weekend date",
DateTime => "Weekday date",
null => "No date",
_ => "Not a date"
};
Följande metod ger samma resultat med en serie imperativa förgreningssatser:
static string DescribeDateWithBranches(object? value)
{
if (value is DateTime date)
{
if (date.DayOfWeek == DayOfWeek.Saturday ||
date.DayOfWeek == DayOfWeek.Sunday)
{
return "Weekend date";
}
return "Weekday date";
}
if (value is null)
{
return "No date";
}
return "Not a date";
}
Den mönsterbaserade versionen håller ihop möjliga resultat när flera grenar testar ett värdes typ och form. Den imperativa versionen gör varje test och retursteg explicit. För ett villkor kan båda formerna se likadana ut. När antalet relaterade grenar växer kan mönster göra alternativen enklare att jämföra.