In modernen Anwendungen kommt es häufiger vor, dass Daten aus verschiedenen Quellen verarbeitet werden müssen.
Seit C# 7 gibt es die Möglichkeit, dieses Vorhaben mit Hilfe von Tupeln zu vereinfachen.
Durch Tupel ist es möglich, eine Gruppierung von Werten zu erstellen, die normalerweise aus verschiedenen Objekten oder Datentypen geholt werden müssten.
In diesem Artikel werden die Funktionen von Tupeln durch Beispiele verdeutlicht, sowie Vor- und Nachteile beleuchtet.
Tupel sind Datenstrukturen, die über eine vordefinierte Anzahl von Elementen verfügen.
Im Gegensatz zu anderen Strukturen wie Listen oder Arrays können Tupel unterschiedlich aufgebaut werden und über mehrere Datentypen verfügen.
1// Erstellen über die Definition der Werte
2(int, string) contact = (1, "Max Mustermann");
3Console.WriteLine($"{contact.Item2} hat die ID {contact.Item1}");
4
5// Erstellen über die Tuple-Klasse
6Tuple<int, string> secondContact = new Tuple<int, string>(1, "Max Mustermann");
7
8// Benennung der Werte
9var contact3 = (ID: 1, Name: "Max Mustermann");
10Console.WriteLine($"{contact3.Name} hat die ID {contact3.ID}");
11// Ausgabe: Max Mustermann hat die ID 1
1private static (int, string) GetPosition()
2{
3 return (1, "position");
4}
5
6private static (int position, string name) GetPositionV2()
7{
8 return (1, "position");
9}
10
11var position = GetPosition();
12var secondPosition = GetPositionV2();
1// Tupel mit mehreren Werten
2var adress = (Street: "Musterstraße", Number: 1, Zip: 12345, City: "Musterstadt");
3Console.WriteLine($"{adress.Street} {adress.Number}, {adress.Zip} {adress.City}");
Ein Kunde möchte, dass für jeden Kontakt in unserer Anwendung die zugehörigen Bilder aus einem Storage geladen werden, um diese später im Frontend auszugeben.
Hierfür brauchen wir die Zuordnung der ID und der Liste mit Bildern des Kontaktes.
In unserem AssetService
können wir eine Methode definieren, die uns eine Kontakt-ID mit den zugehörigen Bildern in einem Tupel zurückliefert.
1namespace MultipleReturns
2{
3 public interface IAssetService
4 {
5 List<Tuple<int, byte[]>> GetAssignedAssets(List<int> contactIDs);
6 }
7}
8
9namespace MultipleReturns
10{
11 /// <summary>
12 /// Service zum Laden der Assets von Kontakten
13 /// </summary>
14 public class AssetService : IAssetService
15 {
16 public List<Tuple<int, byte[]>> GetAssignedAssets(List<int> contactIDs)
17 {
18 var result = new List<Tuple<int, byte[]>>();
19 // Die Assets für die angegebenen Kontakte laden
20 // Die Assets zu der Liste mit den Ergebnissen hinzufügen
21
22 return result;
23 }
24 }
25}
Durch Tupel können mehrere Werte einfach gruppiert werden, ohne dass eine separate Klasse oder Struktur definiert werden muss. Dies kann den Code, bei kleineren oder temporären Datensammlungen, vereinfachen.
Mit der Einführung von benannten Tupeln in C# 7.0 kann Code lesbarer gemacht werden, indem den Tupel-Elementen Namen zugewiesen werden. Dies verbessert die Verständlichkeit des Codes, insbesondere im Kontext der Daten, die das Tupel repräsentiert.
Tupel bieten eine saubere und typsichere Möglichkeit, mehrere Werte aus einer Methode zurückzugeben, ohne auf out
-Parameter oder das Definieren einer zusätzlichen Klasse zurückgreifen zu müssen.
Durch die Verwendung von Tupeln können Methodensignaturen vereinfacht werden, indem mehrere Ausgabeparameter in einem einzigen Rückgabetyp zusammengefasst werden. Dies reduziert die Komplexität von Methodenaufrufen und macht den Code übersichtlicher.
Der übermäßige Einsatz von Tupeln kann den Code schwer verständlich machen, da die Bedeutung jedes Tupel-Elements ohne ausreichende Dokumentation nicht immer klar ist.
Änderungen an der Struktur eines Tupels können sich auf viele Bereiche des Codes auswirken, insbesondere wenn das Tupel als Rückgabetyp einer Methode verwendet wird. Das Hinzufügen, Entfernen oder Ändern von Elementen kann eine Fülle von Änderungen erforderlich machen.
Tupel fördern möglicherweise nicht die Wiederverwendbarkeit von Code im Vergleich zu Klassen oder Strukturen, da Tupel tendenziell spezifisch für den Kontext sind, in dem sie verwendet werden. Für allgemeinere Datenstrukturen, die in verschiedenen Teilen einer Anwendung wiederverwendet werden können, sind Klassen oder Strukturen oft die bessere Wahl.
Obwohl Tupel in vielen Szenarien effizient sind, kann die Erstellung großer Mengen von Tupeln oder die häufige Erstellung und Zerstörung von Tupeln in leistungskritischen Anwendungen zu einem erhöhten Speicherverbrauch und zu einer höheren Last auf dem Garbage Collector führen, insbesondere im Vergleich zu einfachen Werttypen oder wiederverwendeten Objekten.
Tupel sind vor allem nützlich für die Rückgabe von mehreren Werten aus einer Methode oder als temporäre Verknüpfung von Werten. Wenn ein Tupel an vielen Stellen verwendet werden muss, würde ich aufgrund der Wartbarkeit eher dazu raten, eine Klasse zu erstellen.
GitHub-Beispiel: https://github.com/NoelJanH/MultipleReturns