Demontera tupler och andra typer

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.

En uppdelning tilldelar enskilda delar av ett värde – dess komponenter – till flera variabler i en enda åtgärd. En tupels komponenter är dess element, exponerade efter position. En annan typ kan exponera komponenter genom att definiera en Deconstruct metod. Positionella records, som deklarerar sina egenskaper som konstruktorliknande parametrar, får automatiskt en Deconstruct-metod.

Dekonstruera tupplar

Anta att en metod returnerar en tuppl med stadsdata. Du kan läsa varje komponent en i taget:

var cityData = QueryCityData("New York City");
var city = cityData.City;
var population = cityData.Population;
var area = cityData.Area;

En destrukturering tilldelar dessa komponenter i ett steg:

(string city, int population, double area) = QueryCityData("New York City");

Du kan också låta C# härleda variabeltyperna:

var (city, population, area) = QueryCityData("New York City");

En dekonstruktion kan blanda befintliga variabler, nyligen deklarerade variabler och kasserade värden i en tilldelning:

(city, var population, _) = QueryCityData("New York City");

Välj den form som gör koden enklast att läsa. En enda var före parenteserna är ofta den tydligaste underförstådda formen. Du kan också blanda explicita typer och var inom parenteserna, men det formuläret är vanligtvis svårare att skanna. Om du bara behöver vissa värden använder du discards i stället för att utelämna positioner.

Ignorera onödiga värden med discards

Varje genererat värde måste radas upp med en position på vänster sida av tilldelningen. När du inte behöver en eller flera positioner använder du _ för att ignorera:

var (_, _, population1960, _, population2010) = QueryPopulationDataForYears(
    "New York City", 1960, 2010);

Här returnerar tuppeln stadsnamnet, två år och två befolkningsvärden. Dekonstruktionen behåller endast populationsvärdena eftersom beräkningen endast använder dessa komponenter.

Dekonstruera användardefinierade typer

En klass, en struct eller ett gränssnitt kan stödja dekonstruktion genom att deklarera en Deconstruct metod. Varje komponent blir en out parameter, vilket gör att metoden kan tilldela tillbaka ett värde till anroparens variabel utan att returnera den. Eftersom varje komponent returneras via en out parameter returnerar själva metoden void:

public void Deconstruct(out string firstName, out string middleName, out string lastName)
{
    firstName = FirstName;
    middleName = MiddleName;
    lastName = LastName;
}

Du kan sedan destrukturera en instans direkt:

var (firstName, middleName, lastName) = passenger;

En typ kan ge flera Deconstruct överlagrade metoder med olika aritet – antalet out parametrar som metoden deklarerar – så att anropare kan välja hur många komponenter som ska hämtas:

public void Deconstruct(out string firstName, out string lastName)
{
    firstName = FirstName;
    lastName = LastName;
}

public void Deconstruct(out string firstName, out string middleName, out string lastName)
{
    firstName = FirstName;
    middleName = MiddleName;
    lastName = LastName;
}

public void Deconstruct(out string firstName, out string lastName, out string city, out string state)
{
    firstName = FirstName;
    lastName = LastName;
    city = City;
    state = State;
}

Två överlagrade metoder med samma antal out parametrar är tvetydiga. Kompilatorn rapporterar ett fel för det tvetydiga anropet, så särskilj överlagrade metoder efter aritet, inte bara efter parametertyper.

Kasseringar fungerar också med användardefinierad dekonstruktion. Mer information om diskarderade värden i allmänhet finns i Diskarderade värden och diskarderingsmönstret:

var (firstName, _, city, _) = passenger;

Dela upp poster

En positionell post record eller record struct deklarerar sina egenskaper som parametrar i själva typdeklarationen, ungefär som en konstruktor. Kompilatorn genererar en Deconstruct metod åt dig, med out parametrar som matchar dessa positionsparametrar:

var (city, highTempC, lowTempC) = forecast;

Endast positionsparametrarna deltar i den genererade dekonstrueringen. Ytterligare egenskaper som du deklarerar någon annanstans i posten läggs inte till automatiskt.

Använd deconstruction på datatyper som du inte äger

Om du inte kan ändra en typ kan du fortfarande stödja dekonstruktion genom att skriva en tilläggsmetod – en statisk metod som lägger till en Deconstruct-metod till en typ som du inte själv har definierat, som om den vore medlem av den typen. När du har lagt till metoden kan valfritt Uri värde använda dekonstruktionssyntax:

static class UriExtensions
{
    public static void Deconstruct(this Uri uri, out string scheme, out string host, out int port)
    {
        scheme = uri.Scheme;
        host = uri.Host;
        port = uri.Port;
    }
}

Samma tvetydighetsregel gäller här: två tilläggsmetoder Deconstruct med samma aritet är tvetydiga. Tvetydighet kan också uppstå mellan en instansmetod Deconstruct och en tilläggsmetod med samma antal parametrar. I båda fallen rapporterar kompilatorn ett fel för det tvetydiga anropet.

Inbyggd destrukturering av systemtyper

Vissa systemtyper definierar redan en Deconstruct metod med samma mekanism som du skulle använda för dina egna typer. Till exempel stöder System.Collections.Generic.KeyValuePair<TKey,TValue> dekonstruktion, vilket gör iteration över ordlistor koncis:

foreach (var (repo, commitCount) in repoCommitCounts)
{
    Console.WriteLine($"{repo} had {commitCount:N0} commits in this snapshot.");
}

Dekonstruktion och mönstermatchning

En Deconstruct metod möjliggör även positionsbaserade mönster för den typen. Ett positionsmönster testar och dekonstruerar ett värde i ett steg med samma parentesiserade syntax som en dekonstruktion: person is ("Alice", 30) matchar en Person vars dekonstruerade komponenter är lika med dessa värden. Detta skiljer sig från ett egenskapsmönster som testar namngivna egenskaper direkt, till exempel person is { Name: "Alice", Age: 30 }. Egenskapsmönster är vanligtvis tydligare för objektstrukturer eftersom medlemsnamn förklarar testet. Positionsmönster är starkast när ordningen redan har betydelsen, till exempel med tupler eller andra små ordnade värden.

Se även