Tupel (Visual Basic)

Ab Visual Basic 2017 bietet die Visual Basic Sprache integrierte Unterstützung für Tuples, die das Erstellen von Tuples und den Zugriff auf die Elemente von Tuples vereinfachen. Ein Tuple ist eine leichte Datenstruktur, die eine bestimmte Anzahl und Sequenz von Werten aufweist. Wenn Sie das Tuple instanziieren, definieren Sie die Zahl und den Datentyp jedes Werts (oder Elements). Beispielsweise verfügt ein 2-Tuple (oder paar) über zwei Elemente. Der erste Wert kann ein Wert sein, während der zweite Stringein Boolean . Da Tuples es einfach machen, mehrere Werte in einem einzelnen Objekt zu speichern, werden sie häufig als einfache Methode verwendet, um mehrere Werte aus einer Methode zurückzugeben.

Wichtig

Tuple-Unterstützung erfordert den ValueTuple Typ. Wenn die .NET Framework 4.7 nicht installiert ist, müssen Sie das NuGet Paket System.ValueTuplehinzufügen, das im NuGet Katalog verfügbar ist. Ohne dieses Paket erhalten Sie möglicherweise einen Kompilierungsfehler ähnlich wie "Vordefinierter Typ "ValueTuple(Of,,,)" ist nicht definiert oder importiert.

Instanziieren und Verwenden eines Tuples

Sie instanziieren ein Tuple, indem Sie die Trennzeichenwerte in Klammern einschließen. Jede dieser Werte wird dann zu einem Feld des Tuples. Der folgende Code definiert z. B. ein Triple (oder 3-Tuple) mit Date einem ersten Wert, String einem zweiten und Boolean einem dritten.

Dim holiday = (#07/04/2017#, "Independence Day", True)

Standardmäßig besteht der Name jedes Felds in einem Tuple aus der Zeichenfolge Item zusammen mit der 1-basierten Position des Felds im Tuple. Für dieses 3-Tuple ist das Feld , das Feld ist , und das DateStringBoolean Feld Item2ist .Item3Item1 Im folgenden Beispiel werden die Werte von Feldern der Tuple-Instanziierung in der vorherigen Codezeile angezeigt.

Console.WriteLine($"{holiday.Item1} is {holiday.Item2}" +
                  $"{If(holiday.Item3, ", a national holiday", String.Empty)}")
' Output: 7/4/2017 12:00:00 AM Is Independence Day, a national holiday

Die Felder eines Visual Basic Tuples sind Schreibzugriff. Nachdem Sie ein Tuple instanziiert haben, können Sie die Werte ändern. Im folgenden Beispiel werden zwei der drei Felder des im vorherigen Beispiel erstellten Tuples geändert und das Ergebnis angezeigt.

holiday.Item1 = #01/01/2018#
holiday.Item2 = "New Year's Day"
Console.WriteLine($"{holiday.Item1} is {holiday.Item2}" +
                  $"{If(holiday.Item3, ", a national holiday", String.Empty)}")
' Output: 1/1/2018 12:00:00 AM Is New Year's Day, a national holiday

Instanziieren und Verwenden eines benannten Tuples

Anstatt Standardnamen für die Felder eines Tuples zu verwenden, können Sie ein benanntes Tuple instanziieren, indem Sie Ihre eigenen Namen den Elementen des Tuples zuweisen. Auf die Felder des Tuples kann dann von ihren zugewiesenen Namen oder ihren Standardnamen zugegriffen werden. Im folgenden Beispiel wird das gleiche 3-Tuple wie zuvor instanziiert, außer dass es explizit das erste FeldEventDate, das zweite und das dritte NameIsHolidaybenannt. Anschließend werden die Feldwerte angezeigt, sie geändert und die Feldwerte erneut angezeigt.

Dim holiday = (EventDate:=#07/04/2017#, Name:="Independence Day", IsHoliday:=True)
Console.WriteLine($"{holiday.EventDate} Is {holiday.Name}" +
                  $"{If(holiday.IsHoliday, ", a national holiday", String.Empty)}")
holiday.Item1 = #01/01/2018#
holiday.Item2 = "New Year's Day"
Console.WriteLine($"{holiday.Item1} is {holiday.Item2}" +
                  $"{If(holiday.Item3, ", a national holiday", String.Empty)}")
' The example displays the following output:
'   7/4/2017 12:00:00 AM Is Independence Day, a national holiday
'   1/1/2018 12:00:00 AM Is New Year's Day, a national holiday

Sie können auch die Tuplenamen als Teil der Typdeklaration einer Variable, eines Felds oder eines Parameters angeben:

Dim holiday As (EventDate As Date, Name As String, IsHoliday As Boolean) =
    (#07/04/2017#, "Independence Day", True)
Console.WriteLine(holiday.Name)
' Output: Independence Day

oder im Rückgabetyp einer Methode.

Dies ist besonders nützlich bei der Bereitstellung von Tuples an einen Sammlungs-Initializer; Die Tuplenamen können als Teil der Typdeklaration der Auflistung bereitgestellt werden:

Dim events As New List(Of (EventDate As Date, Name As String, IsHoliday As Boolean)) From {
    (#07/04/2017#, "Independence Day", True),
    (#04/22/2017#, "Earth Day", False)
}
Console.WriteLine(events(1).IsHoliday)
' Output: False

Abgeleitete Tupelelementnamen

Ab Visual Basic 15.3 können Visual Basic die Namen von Tupleelementen herleiten; Sie müssen sie nicht explizit zuweisen. Abgeleitete Tuplenamen sind nützlich, wenn Sie ein Tuple aus einer Reihe von Variablen initialisieren und den Tuple-Elementnamen als Variablennamen verwenden möchten.

Im folgenden Beispiel wird ein stateInfo Tuple erstellt, das drei explizit benannte Elemente, state, stateNameund .capital Beachten Sie, dass in der Benennung der Elemente die Tuple-Initialisierungsanweisung einfach die benannten Elemente den Werten der identisch benannten Variablen zuweisen.

Const state As String = "MI"
Const stateName As String = "Michigan"
Const capital As String = "Lansing"
Dim stateInfo = (state:=state, stateName:=stateName, capital:=capital)
Console.WriteLine($"{stateInfo.stateName}: 2-letter code: {stateInfo.state}, Capital {stateInfo.capital}")
' The example displays the following output:
'      Michigan: 2-letter code: MI, Capital Lansing

Da Elemente und Variablen denselben Namen haben, kann der Visual Basic Compiler die Namen der Felder wie im folgenden Beispiel festlegen.

Const state As String = "MI"
Const stateName As String = "Michigan"
Const capital As String = "Lansing"
Dim stateInfo = (state, stateName, capital)
Console.WriteLine($"{stateInfo.stateName}: 2-letter code: {stateInfo.State}, Capital {stateInfo.capital}")
' The example displays the following output:
'      Michigan: 2-letter code: MI, Capital Lansing

Um abgeleitete Tupleelementnamen zu aktivieren, müssen Sie die Version des Visual Basic Compilers definieren, die in Ihrer Visual Basic Projektdatei (*.vbproj) verwendet werden soll:

<PropertyGroup>
  <LangVersion>15.3</LangVersion>
</PropertyGroup>

Die Versionsnummer kann jede Version des Visual Basic Compilers ab 15.3 sein. Anstatt eine bestimmte Compilerversion zu codieren, können Sie auch "Neueste" als Wert LangVersion angeben, der mit der neuesten Version des Visual Basic Compilers auf Ihrem System installiert ist.

Weitere Informationen finden Sie unter Festlegen der Visual Basic Sprachversion.

In einigen Fällen kann der Visual Basic Compiler den Tuple-Elementnamen nicht aus dem Kandidatennamen abgeleitet werden, und das Tuplefeld kann nur mit seinem Standardnamen, zItem1Item2. B. , usw. referenziert werden. Dazu gehören:

  • Der Kandidatname entspricht dem Namen eines Tuplemitglieds, zItem3. B. , oder RestToString.

  • Der Kandidatname wird im Tuple dupliziert.

Wenn die Feldnamenzuleitung fehlschlägt, generiert Visual Basic keinen Compilerfehler, oder es wird zur Laufzeit eine Ausnahme ausgelöst. Stattdessen müssen Tuplefelder durch ihre vordefinierten Namen wie Item1 z. B. und Item2.

Tuples im Vergleich zu Strukturen

Ein Visual Basic Tuple ist ein Werttyp, der eine Instanz eines der generischen Typen von System.ValueTuple ist. Beispielsweise ist das holiday in dem vorherigen Beispiel definierte Tuple eine Instanz der ValueTuple<T1,T2,T3> Struktur. Es ist so konzipiert, dass es sich um einen einfachen Container für Daten handelt. Da das Tuple darauf abzielt, ein Objekt mit mehreren Datenelementen zu erstellen, fehlt es an einigen der Features, die eine benutzerdefinierte Struktur haben könnte. Dazu zählen unter anderem folgende Einstellungen:

  • Benutzerdefinierte Elemente. Sie können ihre eigenen Eigenschaften, Methoden oder Ereignisse für ein Tuple nicht definieren.

  • Validierung. Sie können die Daten, die Feldern zugewiesen sind, nicht überprüfen.

  • Unveränderlichkeit. Visual Basic Tuples sind stummschaltbar. Im Gegensatz dazu kann eine benutzerdefinierte Struktur steuern, ob eine Instanz stummschaltbar oder unveränderlich ist.

Wenn benutzerdefinierte Elemente, Eigenschafts- und Feldüberprüfungen oder Unveränderlichkeit wichtig sind, sollten Sie die Visual Basic Structure-Anweisung verwenden, um einen benutzerdefinierten Werttyp zu definieren.

Ein Visual Basic Tuple erbt die Elemente des WertTuple-Typs. Zusätzlich zu seinen Feldern umfassen diese die folgenden Methoden:

Methode BESCHREIBUNG
CompareTo Vergleicht das aktuelle Tuple mit einer anderen Tuple mit derselben Anzahl von Elementen.
Equals Bestimmt, ob das aktuelle Tuple gleich einem anderen Tuple oder Objekt ist.
GetHashCode Berechnet den Hashcode für die aktuelle Instanz.
ToString Gibt die Zeichenfolgendarstellung dieses Tuples zurück, die das Formular (Item1, Item2...)verwendet, wobei Item1 und die Werte der Tuplefelder dargestellt werden Item2 .

Darüber hinaus implementieren die ValueTuple-TypenIStructuralComparable implementieren und IStructuralEquatable Schnittstellen, mit denen Sie benutzerdefinierte Vergleiche definieren können.

Zuweisung und Tupel

Visual Basic unterstützt die Zuordnung zwischen Tupletypen, die dieselbe Anzahl von Feldern aufweisen. Die Feldtypen können konvertiert werden, wenn eine der folgenden Werte wahr ist:

  • Das Quell- und Zielfeld ist vom gleichen Typ.

  • Eine Erweiterung (oder implizite) Konvertierung des Quelltyps in den Zieltyp wird definiert.

  • Option Strict ist On, und eine schmale (oder explizite) Konvertierung des Quelltyps in den Zieltyp wird definiert. Diese Konvertierung kann eine Ausnahme auslösen, wenn der Quellwert außerhalb des Bereichs des Zieltyps liegt.

Andere Konvertierungen gelten nicht für Zuordnungen. Sehen wir uns die Arten von Zuweisungen an, die zwischen Tupeltypen zulässig sind.

Berücksichtigen Sie diese Variablen, die in den folgenden Beispielen verwendet werden:

' The number and field types of all these tuples are compatible. 
' The only difference Is the field names being used.
Dim unnamed = (42, "The meaning of life")
Dim anonymous = (16, "a perfect square")
Dim named = (Answer:=42, Message:="The meaning of life")
Dim differentNamed = (SecretConstant:=42, Label:="The meaning of life")

Die ersten beiden Variablen und anonymous, unnamed haben keine semantischen Namen für die Felder. Ihre Feldnamen sind die Standardeinstellung Item1 und Item2. Die letzten beiden Variablen und nameddifferentName weisen semantische Feldnamen auf. Beachten Sie, dass diese zwei Tupel unterschiedliche Namen für die Felder besitzen.

Alle vier dieser Tuples verfügen über die gleiche Anzahl von Feldern (als "Arität" bezeichnet), und die Typen dieser Felder sind identisch. Daher funktionieren alle Zuweisungen:

' Assign named to unnamed.
named = unnamed

' Despite the assignment, named still has fields that can be referred to as 'answer' and 'message'.
Console.WriteLine($"{named.Answer}, {named.Message}")
' Output:  42, The meaning of life

' Assign unnamed to anonymous.
anonymous = unnamed
' Because of the assignment, the value of the elements of anonymous changed.
Console.WriteLine($"{anonymous.Item1}, {anonymous.Item2}")
' Output:   42, The meaning of life

' Assign one named tuple to the other.
named = differentNamed
' The field names are Not assigned. 'named' still has 'answer' and 'message' fields.
Console.WriteLine($"{named.Answer}, {named.Message}")
' Output:   42, The meaning of life

Beachten Sie, dass die Namen der Tupel nicht zugewiesen sind. Die Werte der Felder werden nach der Reihenfolge der Felder im Tupel zugewiesen.

Beachten Sie schließlich, dass wir das Tuple dem Tuple zuweisen können, auch wenn das named erste Feld ein ist, und das erste Feld conversionnamed ist ein LongInteger.conversion Diese Zuordnung ist erfolgreich, da die Integer Konvertierung in eine Long Erweiterung erfolgt.

' Assign an (Integer, String) tuple to a (Long, String) tuple (using implicit conversion).
Dim conversion As (Long, String) = named
Console.WriteLine($"{conversion.Item1} ({conversion.Item1.GetType().Name}), " +
                  $"{conversion.Item2} ({conversion.Item2.GetType().Name})")
' Output:      42 (Int64), The meaning of life (String)

Tuples mit unterschiedlichen Zahlen von Feldern sind nicht zuweisen:

' Does not compile.
' VB30311: Value of type '(Integer, Integer, Integer)' cannot be converted
'          to '(Answer As Integer, Message As String)'
var differentShape = (1, 2, 3)
named = differentShape

Tupel als Methodenrückgabewert

Eine Methode kann nur einen einzelnen Wert zurückgeben. Häufig möchten Sie jedoch einen Methodenaufruf verwenden, um mehrere Werte zurückzugeben. Es gibt mehrere Möglichkeiten, um diese Einschränkung zu umgehen:

  • Sie können eine benutzerdefinierte Klasse oder Struktur erstellen, deren Eigenschaften oder Felder Werte darstellen, die von der Methode zurückgegeben werden. Dies ist eine schwergewichtige Lösung; es erfordert, dass Sie einen benutzerdefinierten Typ definieren, dessen einziger Zweck es ist, Werte aus einem Methodenaufruf abzurufen.

  • Sie können einen einzelnen Wert aus der Methode zurückgeben und die verbleibenden Werte zurückgeben, indem Sie sie durch Verweis auf die Methode übergeben. Dies umfasst den Aufwand für die Instanziierung einer Variablen und Risiken, die sie versehentlich überschreiben den Wert der Variablen, die Sie durch Verweis übergeben.

  • Sie können ein Tuple verwenden, das eine einfache Lösung zum Abrufen mehrerer Rückgabewerte bereitstellt.

Beispielsweise geben die TryParse-Methoden in .NET einen Boolean Wert zurück, der angibt, ob der Analysevorgang erfolgreich war. Das Ergebnis des Analysevorgangs wird in einer Variablen zurückgegeben, die durch Verweis auf die Methode übergeben wird. Normalerweise sieht ein Aufruf einer Analysemethode wie Int32.TryParse folgt aus:

Dim numericString As String = "123456"
Dim number As Integer
Dim result = Integer.TryParse(numericString, number)
Console.WriteLine($"{If(result, $"Success: {number:N0}", "Failure")}")
'      Output: Success: 123,456

Wir können ein Tuple aus dem Analysevorgang zurückgeben, wenn wir den Aufruf der Int32.TryParse Methode in unsere eigene Methode umschließen. Im folgenden Beispiel NumericLibrary.ParseInteger wird die Int32.TryParse Methode aufgerufen und ein benanntes Tuple mit zwei Elementen zurückgegeben.

Imports System.Globalization

Public Module NumericLibrary
    Public Function ParseInteger(value As String) As (Success As Boolean, Number As Integer)
        Dim number As Integer
        Return (Integer.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, number), number)
    End Function
End Module

Anschließend können Sie die Methode mit Code wie folgt aufrufen:

Dim numericString As String = "123,456"
Dim result = ParseInteger(numericString)
Console.WriteLine($"{If(result.Success, $"Success: {result.Number:N0}", "Failure")}")
Console.ReadLine()
'      Output: Success: 123,456

Visual Basic Tuples und Tuples im .NET Framework

Ein Visual Basic Tuple ist eine Instanz eines der generischen Typen system.ValueTuple, die in den .NET Framework 4.7 eingeführt wurden. Die .NET Framework enthält auch einen Satz generischer System.Tuple-Klassen. Diese Klassen unterscheiden sich jedoch von Visual Basic Tuples und den generischen Typen "System.ValueTuple" auf verschiedene Arten:

  • Die Elemente der Tuple-Klassen sind Eigenschaften namens Item1, Item2usw. In Visual Basic Tuples und den ValueTuple-Typen sind Tupleelemente Felder.

  • Sie können den Elementen einer Tuple-Instanz oder einer ValueTuple-Instanz keine aussagekräftigen Namen zuweisen. Visual Basic ermöglicht Es Ihnen, Namen zuzuweisen, die die Bedeutung der Felder kommunizieren.

  • Die Eigenschaften einer Tuple-Instanz sind schreibgeschützt ; die Tuples sind unveränderlich. In Visual Basic Tuples und den ValueTuple-Typen sind Tuplefelder schreibgeschützt; die Tuples sind stummschaltbar.

  • Die generischen Tuple-Typen sind Referenztypen. Die Verwendung dieser Tuple-Typen bedeutet das Zuordnen von Objekten. Auf dem langsamsten Pfad kann das einen messbaren Einfluss auf die Leistung Ihrer Anwendungen haben. Visual Basic Tuples und die ValueTuple-Typen sind Werttypen.

Erweiterungsmethoden in der TupleExtensions Klasse erleichtern die Konvertierung zwischen Visual Basic Tuples und .NET Tuple-Objekten. Die ToTuple-Methode konvertiert ein Visual Basic Tuple in ein .NET Tuple-Objekt, und die ToValueTuple-Methode konvertiert ein .NET Tuple-Objekt in ein Visual Basic Tuple.

Im folgenden Beispiel wird ein Tuple erstellt, in ein .NET Tuple-Objekt konvertiert und in ein Visual Basic Tuple konvertiert. Im Beispiel wird dieses Tuple dann mit dem ursprünglichen Vergleich verglichen, um sicherzustellen, dass sie gleich sind.

Dim cityInfo = (name:="New York", area:=468.5, population:=8_550_405)
Console.WriteLine($"{cityInfo}, type {cityInfo.GetType().Name}")

' Convert the Visual Basic tuple to a .NET tuple.
Dim cityInfoT = TupleExtensions.ToTuple(cityInfo)
Console.WriteLine($"{cityInfoT}, type {cityInfoT.GetType().Name}")

' Convert the .NET tuple back to a Visual Basic tuple and ensure they are the same.
Dim cityInfo2 = TupleExtensions.ToValueTuple(cityInfoT)
Console.WriteLine($"{cityInfo2}, type {cityInfo2.GetType().Name}")
Console.WriteLine($"{NameOf(cityInfo)} = {NameOf(cityInfo2)}: {cityInfo.Equals(cityInfo2)}")

' The example displays the following output:
'       (New York, 468.5, 8550405), type ValueTuple`3
'       (New York, 468.5, 8550405), type Tuple`3
'       (New York, 468.5, 8550405), type ValueTuple`3
'       cityInfo = cityInfo2 :  True

Siehe auch