Tupel und andere Typen dekonstruieren

Tip

Dieser Artikel ist Teil des Abschnitts "Grundlagen" für Entwickler, die bereits mindestens eine Programmiersprache kennen und C# erlernen. Beginnen Sie mit der Übersicht über den Musterabgleich , wenn Muster für Sie neu sind.

Eine Dekonstruktion weist die einzelnen Teile eines Werts – deren Komponenten – mehreren Variablen in einem einzigen Vorgang zu. Die Komponenten eines Tupels sind seine Elemente, die über ihre Position zugänglich sind. Ein anderer Typ kann Komponenten durch Definieren einer Deconstruct Methode verfügbar machen. Positionale Records, die ihre Eigenschaften als konstruktorähnliche Parameter deklarieren, erhalten automatisch eine Deconstruct-Methode.

Deconstruct Tupel

Angenommen, eine Methode gibt ein Tupel mit Stadtdaten zurück. Sie können jede Komponente jeweils einzeln lesen:

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

Eine Dekonstruktion weist diese Komponenten in einem Schritt zu:

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

Sie können auch zulassen, dass C# die Variablentypen ableiten kann:

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

Eine Dekonstruktion kann vorhandene Variablen, neu deklarierte Variablen und Verwerfungen in einer Zuweisung kombinieren:

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

Wählen Sie die Form aus, mit der der Code am einfachsten zu lesen ist. Ein einzelner var vor den Klammern ist häufig die klarste erschlossene Form. Sie können auch explizite Typen und var innerhalb der Klammern mischen, aber diese Form ist in der Regel schwieriger zu scannen. Wenn Sie nur einige Werte benötigen, verwenden Sie Discards, anstatt Positionen auszulassen.

Nicht benötigte Werte mithilfe von Discards ignorieren

Jeder erzeugte Wert muss mit einer Position auf der linken Seite der Zuweisung ausgerichtet werden. Wenn Sie eine oder mehrere Positionen nicht benötigen, verwenden Sie _ als Platzhalter zum Verwerfen:

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

Hier gibt das Tupel den Stadtnamen, zwei Jahre und zwei Bevölkerungswerte zurück. Die Dekonstruktion behält nur die Populationswerte bei, da bei der Berechnung nur diese Komponenten verwendet werden.

Benutzerdefinierte Typen dekonstruieren

Eine Klasse, Struktur oder Schnittstelle kann die Dekonstruktion durch Deklarieren einer Deconstruct Methode unterstützen. Jede Komponente wird zu einem out Parameter, mit dem die Methode der Variablen des Aufrufers einen Wert wieder zuweisen kann, ohne ihn zurückzugeben. Da jede Komponente über einen out Parameter zurückgegeben wird, gibt die Methode selbst Folgendes zurück void:

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

Anschließend können Sie eine Instanz direkt dekonstruieren:

var (firstName, middleName, lastName) = passenger;

Ein Typ kann mehrere Deconstruct Überladungen mit unterschiedlicher Arität bereitstellen – die Anzahl der out parameter, die die Methode deklariert – sodass Aufrufer auswählen können, wie viele Komponenten abgerufen werden sollen:

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

Zwei Überladungen mit derselben Anzahl von out Parametern sind mehrdeutig. Der Compiler meldet einen Fehler für den mehrdeutigen Aufruf, also unterscheiden Sie Überladungen nach Stelligkeit, nicht nur durch Parametertypen.

Ausschlüsse funktionieren auch mit benutzerdefinierter Dekonstruktion. Weitere Informationen zu Verwerfungen im Allgemeinen finden Sie unter „Verwerfungen“ und das Verwerfungsmuster:

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

Datensätze dekonstruieren

Ein positionaler Datensatz record oder record struct deklariert seine Eigenschaften als Parameter in der Typdeklaration selbst, ähnlich einem Konstruktor. Der Compiler generiert eine Deconstruct Methode für Sie mit out Parametern, die diesen Positionsparametern entsprechen:

var (city, highTempC, lowTempC) = forecast;

Nur die Positionsparameter nehmen an dieser generierten Dekonstruktion teil. Weitere Eigenschaften, die Sie an anderer Stelle im Datensatz deklarieren, werden nicht automatisch hinzugefügt.

Typen dekonstruieren, die Ihnen nicht gehören

Wenn Sie einen Typ nicht ändern können, können Sie die Dekonstruktion weiterhin unterstützen, indem Sie eine Erweiterungsmethode schreiben – eine statische Methode, die einem Typ, der Ihnen nicht gehört, eine Deconstruct-Methode hinzufügt, als wäre sie ein Element dieses Typs. Nachdem Sie die Methode hinzugefügt haben, kann jeder Uri Wert die Dekonstruktionssyntax verwenden:

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

Die gleiche Mehrdeutigkeitsregel gilt hier: Zwei Erweiterungsmethoden Deconstruct mit derselben Arität sind mehrdeutig. Mehrdeutigkeit kann auch zwischen einer Instanzmethode Deconstruct und einer Erweiterungsmethode derselben Stelligkeit auftreten. In beiden Fällen meldet der Compiler einen Fehler für den mehrdeutigen Aufruf.

Integrierte Deconstruction für Systemtypen

Einige Systemtypen definieren bereits eine Deconstruct Methode mit demselben Mechanismus, den Sie für Ihre eigenen Typen verwenden. Zum Beispiel unterstützt System.Collections.Generic.KeyValuePair<TKey,TValue> die Dekonstruktion, wodurch die Wörterbuchiteration prägnant wird:

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

Deconstruction und Musterabgleich

Eine Deconstruct Methode ermöglicht auch Positionsmuster für diesen Typ. Ein Positionsmuster testet und dekonstruiert einen Wert in einem Schritt, wobei die gleiche Klammersyntax wie eine Dekonstruktion verwendet wird: person is ("Alice", 30) stimmt mit einem Person überein, dessen dekonstruierten Komponenten diesen Werten entsprechen. Dies unterscheidet sich von einem Eigenschaftsmuster, das benannte Eigenschaften direkt testet, wie person is { Name: "Alice", Age: 30 }. Eigenschaftsmuster sind in der Regel für Objektformen klarer, da Membernamen den Test erläutern. Positionsmuster sind am stärksten, wenn die Reihenfolge bereits die Bedeutung trägt, z. B. mit Tupeln oder anderen kleinen geordneten Werten.

Siehe auch