CodeGym /Kurse /C# SELF /Benennung von Tuple-Elementen und Dekonstruktion von Tupl...

Benennung von Tuple-Elementen und Dekonstruktion von Tuples

C# SELF
Level 11 , Lektion 2
Verfügbar

1. Tuple-Benennung: Kontext für die Dekonstruktion

In der letzten Vorlesung haben wir schon benannte Tuple-Elemente kennengelernt, die den Code viel lesbarer machen, weil man auf Werte nicht mehr über anonyme Item1, Item2 zugreift, sondern über sprechende Namen (zum Beispiel person.Name). Diese Möglichkeit, Tuple-Elementen Namen zu geben, ist besonders wichtig, wenn sie als Rückgabewerte von Methoden, Parametern oder Properties verwendet werden. Genau die Benennung ist die Schlüsselvoraussetzung für eine bequeme Dekonstruktion, die wir gleich noch genauer anschauen.

Zur Erinnerung: Namen kann man beim Initialisieren des Tuples per Literal vergeben, aber auch in der Signatur des Rückgabewerts einer Methode, eines Properties oder Feldes.

Beispiel mit Methode: Benannte Tuple-Elemente im Rückgabewert einer Methode


public static (int Alter, string Name) GetPetInfo()
{
    return (Alter: 5, Name: "Barsik");
}

// Verwendung:
var info = GetPetInfo();
Console.WriteLine($"{info.Name} — {info.Alter} Jahre");

Beispiel mit Feld/Property: Benannte Tuple-Elemente im Feld/Property


public (int Breite, int Hoehe) BildGroesse = (1024, 768);

Denk dran: Wenn keine Namen explizit vergeben werden, sind die Elemente weiterhin über Item1, Item2 usw. erreichbar. Das kann den Code weniger lesbar machen, besonders wenn das Tuple später noch weiterverwendet wird. Deshalb empfiehlt es sich immer, sinnvolle Namen zu vergeben, wenn der Sinn nicht schon aus dem Kontext klar ist.

2. Dekonstruktion von Tuples

Was ist Dekonstruktion?

Dekonstruktion ist der Prozess, ein Tuple in einzelne Variablen "aufzubrechen", damit man damit bequem weiterarbeiten kann. Also, aus dem Tuple (Alter: 5, Name: "Barsik") werden zwei Variablen: alter und name.

Analogie: Stell dir vor, ein Tuple ist eine Kiste mit beschrifteten Fächern. Dekonstruktion heißt, du packst den Inhalt der Kiste direkt an die richtigen Stellen auf deinem Tisch.

Dekonstruktions-Syntax


var tier = (Alter: 5, Name: "Barsik");
var (alter, name) = tier;
Console.WriteLine($"{name} — {alter} Jahre");
Dekonstruktion eines Tuples in Variablen

Jetzt haben wir zwei Variablen: alter und name. Sie bekommen die Werte aus dem Tuple. Die Namen links (alter, name) müssen nicht mit den Namen im Tuple übereinstimmen, das sind einfach neue lokale Variablen.

Dekonstruktion des Rückgabewerts einer Funktion

Oft werden Tuples genutzt, um mehrere Werte aus einer Funktion zurückzugeben. Da ist die Dekonstruktion besonders praktisch:


public static (double minimum, double maximum) GetMinMax(int[] daten)
{
    int minimum = daten.Min();
    int maximum = daten.Max();
    return (minimum, maximum);
}

var zahlen = new[] { 1, 2, 3, 4, 5 };
var (minWert, maxWert) = GetMinMax(zahlen);
Console.WriteLine($"Minimum: {minWert}, Maximum: {maxWert}");
Dekonstruktion des Rückgabewerts einer Funktion

Achte darauf, dass du bei der Dekonstruktion die Variablen so nennen kannst, wie es im aktuellen Kontext am besten passt.

Dekonstruktion mit var

var (a, b) = (10, 20); // int a = 10, b = 20

Dekonstruktion und discard _

Manchmal braucht man nicht alle Elemente eines Tuples. Man kann sie mit _ (discard) ignorieren. Discard (_) im Tuple ist einfach eine Möglichkeit zu sagen: „Ich weiß, dass hier noch ein Element ist, aber ich brauche es nicht, leg dafür keine Variable an.“

Du dekonstruiert also das Tuple, lässt aber an der Stelle, wo du keinen Wert brauchst, ein „Loch“. Kurz, praktisch und ohne Kompromisse!


var tier = (Alter: 5, Name: "Barsik", IstGluecklich: true);
var (alter, _, istGluecklich) = tier; // nur alter und istGluecklich, Name ignoriert
Dekonstruktion mit discard _

Fun Fact: discard wird oft genutzt, damit man den Namensraum nicht mit unnötigen Variablen zumüllt.

Dekonstruktion in der foreach-Schleife

In C# kann man ein Array von Tuples direkt in der foreach-Schleife mit Dekonstruktion durchgehen:


var tiere = new (string Name, int Alter)[]
{
    ("Barsik", 5),
    ("Musja", 3),
    ("Dzhonni", 7)
};

foreach (var (name, alter) in tiere)
{
    Console.WriteLine($"{name} — {alter} Jahre");
}
Dekonstruktion von Tuples in foreach

3. Wie funktionieren Elementnamen und Typisierung?

Verhalten von benannten Elementen

Die Namen der Tuple-Elemente sind „syntactic sugar“, also eine Vereinfachung für Menschen. Beim Kompilieren werden die Namen zu internen Feldern Item1, Item2 usw., aber IDE und Compiler merken sich die Namen, damit du sie nutzen kannst.

Einfluss auf Typkompatibilität und Casting

Zwei Tuples mit gleicher Anzahl und gleichen Typen, aber unterschiedlichen Namen, gelten für den Compiler als derselbe Typ. Die Namen der Elemente gehören nicht zur Typdefinition:


var t1 = (X: 42, Y: 13);
var t2 = (A: 42, B: 13);
t1 = t2; // OK
Console.WriteLine(t1.X); // 42
Kompatibilität von Tuples mit unterschiedlichen Elementnamen

Aber bei Ausdrücken und IntelliSense-Vorschlägen werden die Namen aus der linken Seite (wohin zugewiesen wird) verwendet, nicht die von rechts.

Implizite und explizite Namensvergabe

Das hatten wir schon, aber zur Erinnerung: Man kann Tuples mit teilweise benannten Elementen erstellen, oder auch ganz ohne Namen – dann heißen sie einfach Item1 usw.


var punkt = (X: 10, 20); // X und Item2
Console.WriteLine(punkt.X);     // 10
Console.WriteLine(punkt.Item2); // 20
Teilweise benanntes Tuple

Tipp: Vergib immer Namen, wenn das Tuple mehr als ein oder zwei Elemente hat oder wenn der Sinn des Werts nicht aus dem Kontext klar ist.

4. Typische Fehler und Besonderheiten bei Namen und Dekonstruktion

Fehler Nr. 1: „Umzug“ von Namen beim Zuweisen verschiedener Tuples
Wenn du zuerst ein Tuple mit bestimmten Namen deklarierst und ihm dann ein anderes Tuple ohne Namen (oder mit anderen Namen) zuweist, zeigt IntelliSense trotzdem die ursprünglichen Namen an. Zum Beispiel:


var original = (X: 1, Y: 2);
var alias = original;            // alias.X == 1, alias.Y == 2

original = (10, 20);             // Tuple ohne Namen
Console.WriteLine(alias.X);      // funktioniert immer noch, aber alias hat weiterhin die alten Namen

Fehler Nr. 2: Doppelte Elementnamen.
Zwei Elementen denselben Namen zu geben, geht nicht – der Compiler meldet „Duplicate tuple element name“:


var schlechtesTuple = (A: 1, A: 2);     // Fehler CS8122: Duplicate tuple element name 'A'

Fehler Nr. 3: Falsche Dekonstruktion bei Elementanzahl.
Bei der Dekonstruktion muss die Anzahl der Variablen genau zur Tuple-Größe passen. Jede Abweichung führt zu einem Fehler:


var tier = (Alter: 5, Name: "Barsik");
var (alter, name, stimmung) = tier;     // Fehler CS8124: Tuple must contain exactly 3 elements

Fehler Nr. 4: Falsche Verwendung von discard _
Das Ignorieren von Elementen mit _ funktioniert für jede Stelle einzeln und „fasst Lücken“ nicht zusammen. Wenn du versuchst, zwei Elemente gleichzeitig mit einem _ zu überspringen, gibt’s einen Fehler:


var daten = (1, 2, 3);
var (_, x, _) = daten;            // Richtig: erstes und drittes Element übersprungen
var (_, _) = daten;               // Fehler CS8124: Tuple must contain exactly 2 elements

Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION