Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 5 Min.

Mehr zu Tupeln

Die mit Visual Basic 15 eingeführten Tupel bündeln zusammengehörende Daten.
© dotnetpro
In der zurückliegenden Ausgabe der dotnetpro haben Sie die ersten Möglichkeiten des Programmierens mit Tupeln unter Visual Basic kennengelernt [1]. Wichtig: Sie benötigen dafür .NET ab Version 4.7 sowie Visual Studio 2017 oder 2019. Wichtigste Einschränkung: Tupel nehmen maximal acht Werte auf. Weiter geht’s jetzt mit der Option, Tupel in Listen zusammenzufassen.Mehrere Tupel mit gleichem Aufbau fassen Sie optional in Listen zusammen. Wie das geht, zeigt die Funktion GetAdressesList in Listing 1, die als Ergebnis eine Liste von Adress-Tupeln mit unbenannten Elementen zurückgibt. Dazu wird zunächst eine Liste angelegt, die dem Rückgabewert entspricht. Dieser Liste mit Namen tList werden dann drei Adress-Tupel hinzugefügt, um dann die Liste abschließend mit Return an das aufrufende Programm zu übergeben. Die folgenden Anweisungen zeigen den Aufruf der Funktion GetAdressesAsList, wobei der Zielvariablen tL der Datentyp durch die Funktion GetAdressesAsList übergeben wird.
Listing 1: GetAdressesAsList
<span class="hljs-keyword">Function</span> GetAdressesAsList() <span class="hljs-keyword">As</span> List(<span class="hljs-keyword">Of</span> Tuple( <br/>  <span class="hljs-keyword">Of</span> <span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>, <span class="hljs-built_in">UInteger</span>, <span class="hljs-built_in">UInteger</span>,<br/>  <span class="hljs-built_in">String</span>)) <br/><br/>  <span class="hljs-keyword">Dim</span> tList <span class="hljs-keyword">As</span> <span class="hljs-keyword">New</span> List(<span class="hljs-keyword">Of</span> Tuple(<span class="hljs-keyword">Of</span> <span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>,<br/>    <span class="hljs-built_in">String</span>, <span class="hljs-built_in">UInteger</span>, <span class="hljs-built_in">UInteger</span>, <span class="hljs-built_in">String</span>)) <br/>  tList.Add(<span class="hljs-keyword">New</span> Tuple(<span class="hljs-keyword">Of</span> <span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>, <br/>    <span class="hljs-built_in">UInteger</span>, <span class="hljs-built_in">UInteger</span>, <span class="hljs-built_in">String</span>)(<span class="hljs-string">"Peter"</span>, <span class="hljs-string">"Pan"</span>, <br/>    <span class="hljs-string">"Goethestraße"</span>, <span class="hljs-number">234</span>, <span class="hljs-number">20323</span>, <span class="hljs-string">"Hamburg"</span>)) <br/>  tList.Add(<span class="hljs-keyword">New</span> Tuple(<span class="hljs-keyword">Of</span> <span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>,<br/>    <span class="hljs-built_in">UInteger</span>, <span class="hljs-built_in">UInteger</span>, <span class="hljs-built_in">String</span>)(<span class="hljs-string">"Maria"</span>, <span class="hljs-string">"Müller"</span>, <br/>    <span class="hljs-string">"Schillerweg"</span>, <span class="hljs-number">76</span>, <span class="hljs-number">80545</span>, <span class="hljs-string">"München"</span>)) <br/>  tList.Add(<span class="hljs-keyword">New</span> Tuple(<span class="hljs-keyword">Of</span> <span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>, <span class="hljs-built_in">String</span>, <br/>    <span class="hljs-built_in">UInteger</span>, <span class="hljs-built_in">UInteger</span>, <span class="hljs-built_in">String</span>)(<span class="hljs-string">"Klaus"</span>, <span class="hljs-string">"Schmidt"</span>, <br/>    <span class="hljs-string">"Glockengasse"</span>, <span class="hljs-number">7</span>, <span class="hljs-number">30567</span>, <span class="hljs-string">"Hannover"</span>)) <br/><br/>  <span class="hljs-keyword">Return</span> tList <br/><span class="hljs-keyword">End</span> <span class="hljs-keyword">Function</span>  

' Datenrückgabe als änderbare Werteliste 
Dim tL = GetAdressesAsList() 
Dim n as String = vbCrLf  ' Neue Zeile
Dim s as String = <span class="hljs-string">" "</span>    ' Leerzeichen

MsgBox(
  <span class="hljs-string">"Anzahl Elemente: "</span> &amp; tL.Count &amp; nZ &amp;   <span class="hljs-string">"1. Element: "</span> &amp; tL(<span class="hljs-number">0</span>).Item1 &amp; s &amp; tL(<span class="hljs-number">0</span>).Item2 &amp; n &amp;   <span class="hljs-string">"2. Element: "</span> &amp; tL(<span class="hljs-number">1</span>).Item1 &amp; s &amp; tL(<span class="hljs-number">1</span>).Item2 &amp; n &amp;   <span class="hljs-string">"3. Element: "</span> &amp; tL(<span class="hljs-number">2</span>).Item1 &amp; s &amp; tL(<span class="hljs-number">2</span>).Item2, ...) 

Tupellisten nachträglich bearbeiten

Mithilfe der Methode Add der Tupelliste tL können Sie weitere Adresselemente hinzufügen. Alle Vor- und Nachnamen der erweiterten Liste werden per Meldung angezeigt (Bild 1).
Ausgabeder erweiterten Tupel-Adressliste(Bild 1) © Autor
' Liste erweitern 
tL.Add(New Tuple(Of String, String, String, 
  UInteger, UInteger, String)("Hans", "Friedrich", 
  "Bahnhoftstraße", 104, 60489, "Frankfurt")) 

MsgBox(
  "Anzahl Elemente: " &amp; tL.Count &amp; n &amp;   "1. Element: " &amp; tL(0).Item1 &amp; s &amp; tL(0).Item2 &amp; n &amp;   "2. Element: " &amp; tL(1).Item1 &amp; s &amp; tL(1).Item2 &amp; n &amp;   "3. Element: " &amp; tL(2).Item1 &amp; s &amp; tL(2).Item2 &amp; n &amp;   "4. Element: " &amp; tL(3).Item1 &amp; s &amp; tL(3).Item2, ...) 
Mit RemoveAt entfernen Sie ein beliebiges Listenelement über den angegebenen Index – in Bild 2 wurde das Element mit dem Index 1 (Maria Müller) entfernt und das Ergebnis per Dialog angezeigt.
Die gekürzteTupel-Adressliste(Bild 2) © Autor
' Liste um einen Eintrag kürzen 
tL.RemoveAt(1) 
MsgBox( 
  "Anzahl Elemente: " &amp; tL.Count &amp; n &amp; 
  "1. Element: " &amp; tL(0).Item1 &amp; s &amp; tL(0).Item2 &amp; n &amp; 
  "2. Element: " &amp; tL(1).Item1 &amp; s &amp; tL(1).Item2 &amp; n &amp; 
  "3. Element: " &amp; tL(2).Item1 &amp; s &amp; tL(2).Item2, ... ) 
 
Mit einer For-Each-Anweisung iterieren Sie durch die Elemente einer Tupelliste. Im folgenden Beispiel werden die Tupel nacheinander verarbeitet und per Dialog angezeigt.

Dim Counter As Integer = -1 
For Each i As Tuple(Of String, String, String, UInteger, 
  UInteger, String) In tL
  With i 
  Counter += 1 
  MsgBox("Element: " &amp; Counter &amp; n &amp; 
    "Vorname: " &amp; i.Item1 &amp; n &amp; 
    "Nachname: " &amp; i.Item2 &amp; n &amp; 
    "Straße: " &amp; i.Item3 &amp; n &amp; 
    "Hausnummer: " &amp; i.Item4 &amp; n &amp; 
    "PLZ: " &amp; i.Item5 &amp; n &amp; "Ort: " &amp; i.Item6, ...) 
 End With 
Next 
 
Bleibt anzuführen, dass auch Listen bereits diverse Methoden bieten (zum Beispiel Sort), die hier aber nicht im Detail behandelt werden sollen.

Tupel bearbeiten, klonen und ändern

Tupel lassen sich bearbeiten und können kopiert oder geklont werden (als Wertekopie/-klon). Um das bereits für Maria Müller eingerichtete Tupel mit benannten Elementnamen zu kopieren, legen Sie eine neue Variable an (hier MariaMüller2) und weisen dieser den Wert von MariaMüller zu. Mit Equals ist der unmittelbare Vergleich der Tupel möglich. Wie erwartet, werden beide Inhalte als gleich eingestuft.

Dim MariaMüller2 = MariaMüller 
If MariaMüller.Equals(MariaMüller2) Then 
  MsgBox("Die Tupel sind gleich!", ...) 
 
Wollen Sie Elemente eines Tupels bearbeiten, weisen Sie den jeweiligen Elementnamen neue Werte zu. Im folgenden Beispiel werden zum Tupel MariaMüller2 die Daten zu Postleitzahl und Wohnort geändert. Ein Vergleich zeigt, dass keine Gleichheit mehr mit dem kopierten Tupel MariaMüller besteht.

' Werteänderungen 
MariaMüller2.PLZ = 20323 
MariaMüller2.Ort = "Hamburg" 
If MariaMüller.Equals(MariaMüller2) Then 
  MsgBox("Die Tupel sind gleich!", ... )
Else 
  MsgBox("Die Tupel sind ungleich!", ...
End If 
 
Setzen Sie den Wert eines Tupels auf Nothing, so werden lediglich die Werte, nicht aber die Elementnamen und deren Datentypen entfernt. Die nachfolgende MsgBox-Anweisung ist zulässig, da der Wert weiterhin existiert und die Element­anzahl weiterhin gültig ist, nur die Werte sind auf Nothing gesetzt. Dementsprechend liefert der Dialog keinen Inhalt zum abgefragten Nachnamen zurück.

MariaMüller2 = Nothing 
MsgBox(MariaMüller2.Nachname) 
 
Eine Wertzuweisung wie MariaMüller2 = t2 funktioniert dementsprechend nicht, da sich die Struktur, die Datentypen und auch die Elementanzahl eines Tupels (hier MariaMüller2) im Nachhinein nicht mehr ändern lassen.
Iterierter Datensatzeiner Tupel-Adressliste(Bild 3) © Autor

Tupel mit unbenannten Funktionsergebnissen

An dieser Stelle soll gezeigt werden, wie Sie Funktionen definieren, die Tupel mit mehreren unbenannten Elementen als Ergebnis zurückliefern. Der Einfachheit halber wird erneut der Aufbau des Adress-Tupels genutzt. Die Funktion GetAdressAsTupel bekommt einen Indexwert übergeben, über den ein Adressdatensatz gewählt wird. Dieser wird als Tupel angelegt und per Return zurückgegeben (Listing 2).
Listing 2: GetAdressAsTupel
Function GetAdressAsTupel(&lt;br/&gt;  ByVal Number) As (String, String, String, &lt;br/&gt;  UInteger, UInteger, String) &lt;br/&gt;  ' Rückgabe als Item1, Item2 usw... &lt;br/&gt;  Select Case Number &lt;br/&gt;    Case 1 &lt;br/&gt;      Return ("Peter", "Pan", "Goethestraße", 234,&lt;br/&gt;        20323, "Hamburg") &lt;br/&gt;    Case 2 &lt;br/&gt;      Return ("Maria", "Müller", "Schillerweg", 76, &lt;br/&gt;        80545, "München") &lt;br/&gt;    Case 3 &lt;br/&gt;      Return ("Klaus", "Schmidt", "Glockengasse", 7, &lt;br/&gt;        30567, "Hannover") &lt;br/&gt;    Case Else &lt;br/&gt;      Return Nothing &lt;br/&gt;  End Select &lt;br/&gt;End Function  
GetAdressAsTupel2 zeigt die entsprechende Definition auszugsweise, jetzt aber mit dem benannten Datentyp Value­Tuple und dem Of-Operator (Listing 3).
Listing 3: GetAdressAsTupel2 as ValueTuple
Function GetAdressAsTupel2(ByVal Number) As &lt;br/&gt;  ValueTuple(Of String, String, String, UInteger, &lt;br/&gt;  UInteger, String) &lt;br/&gt;&lt;br/&gt;  Select Case Number &lt;br/&gt;    Case 1 &lt;br/&gt;      Return ("Peter", "Pan", "Goethestraße", 234,&lt;br/&gt;        201323, "Hamburg") &lt;br/&gt;    Case 2 &lt;br/&gt;    ...&lt;br/&gt;    Case Else &lt;br/&gt;      Return Nothing &lt;br/&gt;  End Select &lt;br/&gt;End Function  
An dieser Stelle wird mit GetAdressAsTupel der Adressdatensatz mit dem Index 3 abgefragt und in die Variable MariaMüller2 übernommen. GetAdressAsTupel liefert unbenannte Elemente zurück und in MariaMüller2 sind entsprechend der ursprünglichen Kopie benannte Elementnamen angelegt. Dies erklärt, warum sich hier zur Werteausgabe im Meldungsdialog die benannten Elementnamen nutzen lassen.

MariaMüller2 = GetAdressAsTupel(3) 
' dies funktioniert nur, weil die Elementnamen 
' für MariaMüller2 weiterhing gültig sind 
MsgBox("MariaMüller2 – 
   Vorname: " &amp; MariaMüller2.Vorname &amp; n &amp; 
  "Nachname: " &amp; MariaMüller2.Nachname &amp; n &amp; 
  "Straße: " &amp; MariaMüller2.Straße &amp; n &amp; 
  "Hausnummer: " &amp; MariaMüller2.Hausnummer &amp; n &amp; 
  "PLZ: " &amp; MariaMüller2.PLZ &amp; n &amp; 
  "Ort: " &amp; MariaMüller2.Ort, ...) 
 
Richten Sie mit TestOhneElementNamen eine neue Variable ein und weisen Sie dieser das Ergebnis der Funktion GetAdressAsTupel2 zu, hier mit dem Indexwert 1, können Sie die Elementnamen für den Wertezugriff nicht verwenden, sondern müssen in jedem Fall die indizierten Item-Namen nutzen. Jede Änderung wird unmittelbar mit einer Fehlermeldung quittiert.
Die Prozedur ShowTupelAdress(Bild 4) © Autor

' neues Tupel, die Elementnamen sind nicht zugewiesen 
Dim TestOhneElementNamen = GetAdressAsTupel2(1) 
'dementsprechend ist eine Item-Angabe erforderlich 
MsgBox("MariaMüller2 - 
   Vorname: " &amp; TestOhneElementNamen.Item1 &amp; n &amp; 
  "Nachname: " &amp; TestOhneElementNamen.Item2 &amp; n &amp; 
  "Straße: " &amp; TestOhneElementNamen.Item3 &amp; n &amp; 
  "Hausnummer: " &amp; TestOhneElementNamen.Item4 &amp; n &amp; 
  "PLZ: " &amp; TestOhneElementNamen.Item5 &amp; n &amp; 
  "Ort: " &amp; TestOhneElementNamen.Item6, ... ) 

Tupel mit benannten Funktionsergebnissen

Selbstverständlich können Sie Funktionen auch so codieren, dass diese Tupel mit benannten Elementnamen zurückliefern, siehe Listing 4.
Listing 4: GetAdressNamedTupel
Function GetAdressAsNamedTupel(ByVal Number) As ( &lt;br/&gt;  Vorname As String, Nachname As String, &lt;br/&gt;  Straße As String, Hausnummer As UInteger, &lt;br/&gt;  PLZ As UInteger, Ort As String) &lt;br/&gt;&lt;br/&gt;  Select Case Number &lt;br/&gt;    Case 1 &lt;br/&gt;      Return ("Peter", "Pan", "Goethestraße", 234,&lt;br/&gt;        201323, "Hamburg") &lt;br/&gt;    Case 2 ...&lt;br/&gt;    Case Else &lt;br/&gt;      Return Nothing &lt;br/&gt;  End Select &lt;br/&gt;End Function  
Definieren Sie nun eine neue Variable TestMitElement­Namen und weisen Sie dieser das Ergebnis der Funktion Get­AdressAsNamedTuple zu, so werden die Elementnamen wie gewünscht wieder in die Zielvariable übernommen. Sie können also wieder gezielt per Name auf Elemente zugreifen und diese im Dialog ausgeben.

Dim TestMitElementNamen = GetAdressAsNamedTupel(3) 
MsgBox("Klaus Schmidt - 
  Vorname: " &amp; TestMitElementNamen.Vorname &amp; n &amp; 
  "Nachname: " &amp; TestMitElementNamen.Item2 &amp; n &amp; 
  "Straße: " &amp; TestMitElementNamen.Straße &amp; n &amp; 
  "Hausnummer: " &amp; TestMitElementNamen.Item4 &amp; n &amp; 
  "PLZ: " &amp; TestMitElementNamen.PLZ &amp; n &amp; 
  "Ort: " &amp; TestMitElementNamen.Item6, ...) 
 
Die letztgenannte Wertzuweisung können Sie auch in der folgenden Langfassung vornehmen:

Dim TestAdresseMitElementNamen As (Vorname As String, 
  Nachname As String, Straße As String, 
  Hausnummer As UInteger, PLZ As UInteger, 
  Ort As String) = GetAdressAsNamedTupel(3) 

Tupel als Parameter

Bleibt zu zeigen, wie Sie Tupel an Funktionen oder Prozeduren übergeben. Die Funktion ShowTupelAdress übernimmt die Datenstruktur eines Adress-Tupels per Parameter und gibt diese aus.

Sub ShowTupelAdress(ByVal tAdresse As ( 
  String, String, String, UInteger, UInteger, String)) 

  'Typangabe erforderlich 
  Try 
    MsgBox(
      "Vorname: " &amp; tAdresse.Item1 &amp; n &amp; 
      "Nachname: " &amp; tAdresse.Item2 &amp; n &amp; 
      "Straße: " &amp; tAdresse.Item3 &amp; n &amp; 
      "Hausnummer: " &amp; tAdresse.Item4 &amp; n &amp; 
      "PLZ: " &amp; tAdresse.Item5 &amp; n &amp; 
      "Ort: " &amp; tAdresse.Item6, ... ) 
  Catch ex As Exception 
    MsgBox("Bei der Adressverarbeitung ist ein Fehler 
            aufgetreten!", ...) 
  End Try 
End Sub 
 
Das an die Prozedur übergebene Adress-Tupel muss diejenige Datenstruktur aufweisen, die auch in der Parameterliste definiert wurde. Dies ist bei der bereits definierten und initialisierten Variablen PeterPan sichergestellt.

ShowTupelAdress(PeterPan) 

Geschachtelte Tupel

Eine Sonderfunktion soll abschließend noch vorgestellt werden, das Verschachteln von Tupeln. Zwar lassen sich so die über ein einzelnes Tupel verwaltbaren Werte theoretisch auf 64 Elemente (8 mal 8) heraufsetzen, sinnvoll ist das aufgrund der Lesbarkeit aber nicht. Bei diesem Verfahren werden innerhalb eines Tupels bis zu acht untergeordnete Tupel definiert. Das folgende Beispiel erzeugt mit Tupel.Create nur ein untergeordnetes Tupel. Der Elementzugriff erfolgt elementbezogen:

Dim ntVar = Tuple.Create( 
  "erstes Wertepaar", Tuple.Create(23, 45)) 

MsgBox( 
  "Wert Haupttupel:    " &amp; ntVar.Item1 &amp; n &amp; 
  "Untertupel 1. Wert: " &amp; ntVar.Item2.Item1 &amp; n &amp; 
  "           2. Wert: " &amp; ntVar.Item2.Item2, ... ) 
 
Anhand der Beispiele in dieser und der vorangegangenen Folge von Basic Instinct konnten Sie die kompakte Nutzung von Tupeln, die wichtigsten Einsatzmöglichkeiten, aber auch deren Schwachpunkte nachvollziehen. Prinzipiell machen Sie sich das Leben mit Tupeln einfacher, müssen dann aber auch in Kauf nehmen, dass die damit generierten Anwendungen zumindest .NET 4.7 erfordern. Lebensnotwenig sind Tupel generell nicht. Alles, was Sie mit Tupeln erreichen, realisieren Sie auch weiterhin – mitunter mit mehr Aufwand – auf den altbekannten Wegen.
Projektdateien herunterladen

Fussnoten

  1. Andreas Maslo, Werte mit Tupeln zusammenfassen, Teil 1, dotnetpro 6/2019, Seite 136 ff., http://www.dotnetpro.de/A1906BasicInstinct

Neueste Beiträge

DWX hakt nach: Wie stellt man Daten besonders lesbar dar?
Dass das Design von Websites maßgeblich für die Lesbarkeit der Inhalte verantwortlich ist, ist klar. Das gleiche gilt aber auch für die Aufbereitung von Daten für Berichte. Worauf besonders zu achten ist, erklären Dr. Ina Humpert und Dr. Julia Norget.
3 Minuten
27. Jun 2025
DWX hakt nach: Wie gestaltet man intuitive User Experiences?
DWX hakt nach: Wie gestaltet man intuitive User Experiences? Intuitive Bedienbarkeit klingt gut – doch wie gelingt sie in der Praxis? UX-Expertin Vicky Pirker verrät auf der Developer Week, worauf es wirklich ankommt. Hier gibt sie vorab einen Einblick in ihre Session.
4 Minuten
27. Jun 2025
„Sieh die KI als Juniorentwickler“
CTO Christian Weyer fühlt sich jung wie schon lange nicht mehr. Woran das liegt und warum er keine Angst um seinen Job hat, erzählt er im dotnetpro-Interview.
15 Minuten
27. Jun 2025
Miscellaneous

Das könnte Dich auch interessieren

UIs für Linux - Bedienoberflächen entwickeln mithilfe von C#, .NET und Avalonia
Es gibt viele UI-Frameworks für .NET, doch nur sehr wenige davon unterstützen Linux. Avalonia schafft als etabliertes Open-Source-Projekt Abhilfe.
16 Minuten
16. Jun 2025
Mythos Motivation - Teamentwicklung
Entwickler bringen Arbeitsfreude und Engagement meist schon von Haus aus mit. Diesen inneren Antrieb zu erhalten sollte für Führungskräfte im Fokus stehen.
13 Minuten
19. Jan 2017
Evolutionäres Prototyping von Business-Apps - Low Code/No Code und KI mit Power Apps
Microsoft baut Power Apps zunehmend mit Features aus, um die Low-Code-/No-Code-Welt mit der KI und der professionellen Programmierung zu verbinden.
19 Minuten
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige