Tuplas (Visual Basic)
A partir de Visual Basic 2017, el lenguaje Visual Basic ofrece compatibilidad integrada con tuplas que facilita la creación de tuplas y el acceso a los elementos de las tuplas. Una tupla es una estructura de datos ligera que tiene un número específico y una secuencia de valores. Cuando se crea una instancia de la tupla, se define el número y el tipo de datos de cada valor (o elemento). Por ejemplo, una tupla de 2 (o par) tiene dos elementos. El primero podría ser un Boolean valor, mientras que el segundo es un String . Dado que las tuplas hacen que sea fácil almacenar varios valores en un solo objeto, a menudo se usan como una manera ligera de devolver varios valores de un método.
Importante
La compatibilidad con tupla requiere el ValueTuple tipo . Si el .NET Framework 4.7 no está instalado, debe agregar el paquete NuGet , que está disponible en la System.ValueTuple galería de NuGet. Sin este paquete, puede obtener un error de compilación similar al siguiente: "El tipo predefinido 'ValueTuple(Of,,,)' no está definido ni importado".
Creación de instancias y uso de una tupla
Para crear una instancia de una tupla, encierre sus valores delimitados por comas entre paréntesis. Después, cada uno de esos valores se convierte en un campo de la tupla. Por ejemplo, el código siguiente define una triple (o tupla de 3) con un como su primer valor, un como su segundo y un como Date String su Boolean tercero.
Dim holiday = (#07/04/2017#, "Independence Day", True)
De forma predeterminada, el nombre de cada campo de una tupla consta de la cadena junto con la posición basada en uno del campo Item en la tupla. Para esta tupla de 3, el Date campo es , el campo es y el campo es Item1 String Item2 Boolean Item3 . En el ejemplo siguiente se muestran los valores de los campos de la tupla de la que se crearon instancias en la línea de código anterior.
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
Los campos de una Visual Basic tupla son de lectura y escritura; Después de crear una instancia de una tupla, puede modificar sus valores. En el ejemplo siguiente se modifican dos de los tres campos de la tupla creada en el ejemplo anterior y se muestra el resultado.
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
Creación de instancias y uso de una tupla con nombre
En lugar de usar nombres predeterminados para los campos de una tupla, puede crear instancias de una tupla con nombre asignando sus propios nombres a los elementos de la tupla. A continuación, se puede acceder a los campos de la tupla mediante sus nombres asignados o por sus nombres predeterminados. En el ejemplo siguiente se crea una instancia de la misma tupla de 3 que anteriormente, salvo que asigna explícitamente un nombre al primer campo , al segundo y EventDate Name al IsHoliday tercero. A continuación, muestra los valores de campo, los modifica y vuelve a mostrar los valores de campo.
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
Nombres de elementos de tupla inferidos
A partir Visual Basic 15.3, Visual Basic inferir los nombres de los elementos de tupla; no es necesario asignarlos explícitamente. Los nombres de tupla inferidos son útiles al inicializar una tupla a partir de un conjunto de variables y desea que el nombre del elemento de tupla sea el mismo que el nombre de la variable.
En el ejemplo siguiente se crea una tupla que contiene tres elementos con nombre stateInfo explícito, state , y stateName capital . Tenga en cuenta que, al asignar un nombre a los elementos, la instrucción de inicialización de tupla simplemente asigna a los elementos con nombre los valores de las variables con el mismo nombre.
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
Dado que los elementos y variables tienen el mismo nombre, Visual Basic compilador puede deducir los nombres de los campos, como se muestra en el ejemplo siguiente.
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
Para habilitar los nombres de elementos de tupla inferidos, debe definir la versión del compilador de Visual Basic que se usará en el archivo Visual Basic project ( * .vbproj):
<PropertyGroup>
<LangVersion>15.3</LangVersion>
</PropertyGroup>
El número de versión puede ser cualquier versión del compilador Visual Basic a partir de 15.3. En lugar de codificar de forma rígida una versión específica del compilador, también puede especificar "Latest" como valor de para compilar con la versión más reciente del compilador Visual Basic instalado en LangVersion el sistema.
Para obtener más información, vea establecer la Visual Basic versión del lenguaje .
En algunos casos, el compilador de Visual Basic no puede inferir el nombre del elemento de tupla del nombre del candidato y solo se puede hacer referencia al campo de tupla con su nombre predeterminado, como Item1 , Item2 , etc. Estos incluyen:
El nombre del candidato es el mismo que el nombre de un miembro de tupla, como
Item3Rest, oToString.El nombre del candidato está duplicado en la tupla.
Cuando se produce un error en la inferencia de nombres de campo, Visual Basic no genera un error del compilador ni se produce una excepción en tiempo de ejecución. En su lugar, se debe hacer referencia a los campos de tupla mediante sus nombres predefinidos, como Item1 y Item2 .
Tuplas frente a estructuras
Una Visual Basic tupla es un tipo de valor que es una instancia de uno de los tipos genéricos System.ValueTuple. Por ejemplo, la holiday tupla definida en el ejemplo anterior es una instancia de la ValueTuple<T1,T2,T3> estructura . Está diseñado para ser un contenedor ligero para los datos. Dado que la tupla pretende facilitar la creación de un objeto con varios elementos de datos, carece de algunas de las características que podría tener una estructura personalizada. Entre ellas se incluyen las siguientes:
Miembros personalizados. No puede definir sus propias propiedades, métodos o eventos para una tupla.
Validación. No se pueden validar los datos asignados a los campos.
Inmutabilidad. Visual Basic tuplas son mutables. Por el contrario, una estructura personalizada permite controlar si una instancia es mutable o inmutable.
Si los miembros personalizados, la validación de propiedades y campos o la inmutabilidad son importantes, debe usar la instrucción Visual Basic Structure para definir un tipo de valor personalizado.
Una Visual Basic tupla hereda los miembros de su tipo ValueTuple. Además de sus campos, estos incluyen los métodos siguientes:
| Método | Descripción |
|---|---|
| CompareTo | Compara la tupla actual con otra tupla con el mismo número de elementos. |
| Equals | Determina si la tupla actual es igual a otra tupla u objeto. |
| GetHashCode | Calcula el código hash de la instancia actual. |
| ToString | Devuelve la representación de cadena de esta tupla, que tiene la forma , donde y representan los valores de los campos (Item1, Item2...) Item1 de la Item2 tupla. |
Además, los tipos ValueTuple implementan interfaces e , que permiten definir comparadores IStructuralComparable IStructuralEquatable personalizados.
Asignación y tuplas
Visual Basic admite la asignación entre tipos de tupla que tienen el mismo número de campos. Los tipos de campo se pueden convertir si se cumple una de las siguientes condiciones:
Los campos de origen y destino son del mismo tipo.
Se define una conversión de ampliación (o implícita) del tipo de origen al tipo de destino.
Option Strictes y se define una conversión de limitación (o explícita) del tipo de origen al tipoOnde destino. Esta conversión puede producir una excepción si el valor de origen está fuera del intervalo del tipo de destino.
Otras conversiones no se tienen en cuenta para las asignaciones. Echemos un vistazo a los tipos de asignaciones que se permiten entre los tipos de tupla.
Tenga en cuenta estas variables que se usan en los ejemplos siguientes:
' 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")
Las dos primeras variables, unnamed y , no tienen nombres anonymous semánticos proporcionados para los campos. Sus nombres de campo son los predeterminados Item1 y Item2 . Las dos últimas variables y named tienen nombres de campo differentName semánticos. Tenga en cuenta que estas dos tuplas tienen nombres diferentes para los campos.
Las cuatro tuplas tienen el mismo número de campos (denominado "arity"), y los tipos de esos campos son idénticos. Por consiguiente, todas estas asignaciones funcionan:
' 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
Observe que los nombres de las tuplas no se asignan. Los valores de los campos se asignan según el orden de los campos de la tupla.
Por último, observe que podemos asignar la tupla a la named tupla, aunque el primer campo de sea , y el primer conversion named campo de sea Integer conversion Long . Esta asignación se realiza correctamente porque convertir Integer un en es una conversión de Long ampliación.
' 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)
No se pueden asignar tuplas con un número diferente de campos:
' 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
Tuplas como valores devueltos del método
Un método solo puede devolver un solo valor. Sin embargo, con frecuencia, le gustaría que una llamada al método devuelva varios valores. Hay varias maneras de evitar esta limitación:
Puede crear una clase o estructura personalizada cuyas propiedades o campos representan los valores devueltos por el método . Por lo tanto, es una solución pesada; requiere que defina un tipo personalizado cuyo único propósito es recuperar valores de una llamada de método.
Puede devolver un valor único del método y devolver los valores restantes pasándolos por referencia al método . Esto implica la sobrecarga de crear instancias de una variable y corre el riesgo de sobrescribir accidentalmente el valor de la variable que se pasa por referencia.
Puede usar una tupla, que proporciona una solución ligera para recuperar varios valores devueltos.
Por ejemplo, los métodos TryParse de .NET devuelven un valor que indica si la operación de análisis se ha hecho Boolean correctamente. El resultado de la operación de análisis se devuelve en una variable pasada por referencia al método . Normalmente, una llamada al método de análisis como Int32.TryParse es similar a la siguiente:
Dim numericString As String = "123456"
Dim number As Integer
Dim result = Int32.TryParse(numericString, number)
Console.WriteLine($"{If(result, $"Success: {number:N0}", "Failure")}")
' Output: 123,456
Podemos devolver una tupla de la operación de análisis si ajustamos la llamada al Int32.TryParse método en nuestro propio método. En el ejemplo siguiente, NumericLibrary.ParseInteger llama al método y devuelve una Int32.TryParse tupla con nombre con dos elementos.
Imports System.Globalization
Public Module NumericLibrary
Public Function ParseInteger(value As String) As (Success As Boolean, Number As Int32)
Dim number As Integer
Return (Int32.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, number), number)
End Function
End Module
A continuación, puede llamar al método con código como el siguiente:
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 tuplas y tuplas en el .NET Framework
Una Visual Basic tupla es una instancia de uno de los tipos genéricos System.ValueTuple, que se introdujeron en .NET Framework 4.7. El .NET Framework también incluye un conjunto de clases System.Tuple genéricas. Sin embargo, estas clases difieren de Visual Basic tuplas y los tipos genéricos System.ValueTuple de varias maneras:
Los elementos de las clases de tupla son propiedades denominadas
Item1, , y asíItem2sucesivamente. En Visual Basic tuplas y los tipos ValueTuple, los elementos de tupla son campos.No se pueden asignar nombres significativos a los elementos de una instancia de Tuple o de una instancia de ValueTuple. Visual Basic permite asignar nombres que comunican el significado de los campos.
Las propiedades de una instancia de tupla son de solo lectura; las tuplas son inmutables. En Visual Basic tuplas y los tipos ValueTuple, los campos de tupla son de lectura y escritura; las tuplas son mutables.
Los tipos de tupla genéricos son tipos de referencia. El uso de estos tipos de tupla significa asignar objetos. En rutas de acceso activas, esto puede suponer un importante impacto en el rendimiento de la aplicación. Visual Basic tuplas y los tipos ValueTuple son tipos de valor.
Los métodos de extensión de la clase hacen que sea fácil TupleExtensions convertir entre Visual Basic tuplas y objetos de tupla de .NET. El método ToTuple convierte una tupla Visual Basic en un objeto de tupla de .NET y el método ToValueTuple convierte un objeto de tupla de .NET en una tupla Visual Basic.
En el ejemplo siguiente se crea una tupla, se convierte en un objeto de tupla de .NET y se vuelve a convertir en Visual Basic tupla. A continuación, el ejemplo compara esta tupla con la original para asegurarse de que son iguales.
Module Example
Sub Main()
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)}")
Console.ReadLine()
End Sub
End Module
' 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