Tuplas (Visual Basic)Tuples (Visual Basic)

A partir de Visual Basic 2017, el lenguaje de Visual Basic ofrece compatibilidad integrada para tuplas que facilitan la creación de tuplas y el acceso a los elementos de las tuplas.Starting with Visual Basic 2017, the Visual Basic language offers built-in support for tuples that makes creating tuples and accessing the elements of tuples easier. Una tupla es una estructura de datos ligera que tiene un número específico y una secuencia de valores.A tuple is a lightweight data structure that has a specific number and sequence of values. Al crear una instancia de la tupla, se define el número y el tipo de datos de cada valor (o elemento).When you instantiate the tuple, you define the number and the data type of each value (or element). Por ejemplo, una tupla de 2 (o par) tiene dos elementos.For example, a 2-tuple (or pair) has two elements. El primero podría ser un valor Boolean, mientras que el segundo es un String.The first might be a Boolean value, while the second is a String. Dado que las tuplas facilitan el almacenamiento de varios valores en un único objeto, a menudo se usan como una manera ligera de devolver varios valores de un método.Because tuples make it easy to store multiple values in a single object, they are often used as a lightweight way to return multiple values from a method.

Importante

La compatibilidad de tupla requiere el tipo de ValueTuple.Tuple support requires the ValueTuple type. Si el .NET Framework 4,7 no está instalado, debe agregar el paquete NuGet System.ValueTuple, que está disponible en la galería de NuGet.If the .NET Framework 4.7 is not installed, you must add the NuGet package System.ValueTuple, which is available on the NuGet Gallery. Sin este paquete, puede obtener un error de compilación similar al siguiente: "el tipo predefinido ' ValueTuple (de,,,) ' no está definido ni importado".Without this package, you may get a compilation error similar to, "Predefined type 'ValueTuple(Of,,,)' is not defined or imported."

Crear instancias y usar una tuplaInstantiating and using a tuple

Cree una instancia de una tupla mediante la inclusión de los paréntesis de IM de valores delimitados por comas.You instantiate a tuple by enclosing its comma-delimited values im parentheses. Cada uno de esos valores se convierte en un campo de la tupla.Each of those values then becomes a field of the tuple. Por ejemplo, el código siguiente define un triple (o 3-tupla) con un Date como su primer valor, un String como segundo y un Boolean como el tercero.For example, the following code defines a triple (or 3-tuple) with a Date as its first value, a String as its second, and a Boolean as its third.

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

De forma predeterminada, el nombre de cada campo de una tupla se compone de la cadena Item junto con la posición basada en uno de los campos de la tupla.By default, the name of each field in a tuple consists of the string Item along with the field's one-based position in the tuple. En esta tupla de 3, el campo de Date es Item1, el campo de String es Item2 y el campo Boolean es Item3.For this 3-tuple, the Date field is Item1, the String field is Item2, and the Boolean field is Item3. En el ejemplo siguiente se muestran los valores de los campos de la tupla de la que se ha creado una instancia en la línea de código anterior.The following example displays the values of fields of the tuple instantiated in the previous line of code

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 tupla Visual Basic son de lectura y escritura; después de haber creado una instancia de una tupla, puede modificar sus valores.The fields of a Visual Basic tuple are read-write; after you've instantiated a tuple, you can modify its values. En el ejemplo siguiente se modifican dos de los tres campos de la tupla creada en el ejemplo anterior y se muestra el resultado.The following example modifies two of the three fields of the tuple created in the previous example and displays the result.

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

Crear instancias y usar una tupla con nombreInstantiating and using a named tuple

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.Rather than using default names for a tuple's fields, you can instantiate a named tuple by assigning your own names to the tuple's elements. A continuación, se puede tener acceso a los campos de la tupla por sus nombres asignados o por sus nombres predeterminados.The tuple's fields can then be accessed by their assigned names or by their default names. 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 EventDate, el segundo Name y el tercer IsHoliday.The following example instantiates the same 3-tuple as previously, except that it explicitly names the first field EventDate, the second Name, and the third IsHoliday. A continuación, se muestran los valores de campo, se modifican y se muestran los valores de campo de nuevo.It then displays the field values, modifies them, and displays the field values again.

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 inferidosInferred tuple element names

A partir de Visual Basic 15,3, Visual Basic puede deducir los nombres de los elementos de tupla; no es necesario asignarlos explícitamente.Starting with Visual Basic 15.3, Visual Basic can infer the names of tuple elements; you do not have to assign them explicitly. Los nombres de tupla deducidos son útiles cuando se inicializa una tupla a partir de un conjunto de variables y se desea que el nombre del elemento de tupla sea el mismo que el nombre de la variable.Inferred tuple names are useful when you initialize a tuple from a set of variables, and you want the tuple element name to be the same as the variable name.

En el ejemplo siguiente se crea una tupla stateInfo que contiene tres elementos con el nombre explícito, state, stateName y capital.The following example creates a stateInfo tuple that contains three explicitly named elements, state, stateName, and capital. Tenga en cuenta que, al asignar nombres a los elementos, la instrucción de inicialización de tupla simplemente asigna los elementos con nombre a los valores de las variables con el mismo nombre.Note that, in naming the elements, the tuple initialization statement simply assigns the named elements the values of the identically named variables.

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 las variables tienen el mismo nombre, el compilador Visual Basic puede deducir los nombres de los campos, como se muestra en el ejemplo siguiente.Because elements and variables have the same name, the Visual Basic compiler can infer the names of the fields, as the following example shows.

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 Visual Basic que se va a usar en el archivo de proyecto Visual Basic (*. vbproj):To enable inferred tuple element names, you must define the version of the Visual Basic compiler to use in your Visual Basic project (*.vbproj) file:

<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.The version number can be any version of the Visual Basic compiler starting with 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 LangVersion para compilar con la versión más reciente del compilador de Visual Basic instalado en el sistema.Rather than hard-coding a specific compiler version, you can also specify "Latest" as the value of LangVersion to compile with the most recent version of the Visual Basic compiler installed on your system.

Para obtener más información, vea establecer la versión de lenguaje Visual Basic.For more information, see setting the Visual Basic language version.

En algunos casos, el compilador de Visual Basic no puede inferir el nombre del elemento de tupla a partir del nombre del candidato y solo se puede hacer referencia al campo de tupla usando su nombre predeterminado, como Item1, Item2, etc. Entre ellas se incluyen:In some cases, the Visual Basic compiler cannot infer the tuple element name from the candidate name, and the tuple field can only be referenced using its default name, such as Item1, Item2, etc. These include:

  • El nombre del candidato es el mismo que el nombre de un miembro de la tupla, como Item3, Rest o ToString.The candidate name is the same as the name of a tuple member, such as Item3, Rest, or ToString.

  • El nombre del candidato está duplicado en la tupla.The candidate name is duplicated in the tuple.

Cuando se produce un error en la inferencia de nombre de campo, Visual Basic no genera un error del compilador ni se produce una excepción en tiempo de ejecución.When field name inference fails, Visual Basic does not generate a compiler error, nor is an exception thrown at runtime. En su lugar, se debe hacer referencia a los campos de tupla por sus nombres predefinidos, como Item1 y Item2.Instead, tuple fields must be referenced by their predefined names, such as Item1 and Item2.

Tuplas frente a estructurasTuples versus structures

Una tupla Visual Basic es un tipo de valor que es una instancia de uno de los tipos genéricos System. ValueTuple .A Visual Basic tuple is a value type that is an instance of one of the a System.ValueTuple generic types. Por ejemplo, la tupla holiday definida en el ejemplo anterior es una instancia de la estructura ValueTuple<T1,T2,T3>.For example, the holiday tuple defined in the previous example is an instance of the ValueTuple<T1,T2,T3> structure. Está diseñado para ser un contenedor ligero para los datos.It is designed to be a lightweight container for data. 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 puede tener una estructura personalizada.Since the tuple aims to make it easy to create an object with multiple data items, it lacks some of the features that a custom structure might have. Se incluyen los siguientes:These include:

  • Miembros personalizados.Custom members. No puede definir sus propias propiedades, métodos o eventos para una tupla.You cannot define your own properties, methods, or events for a tuple.

  • Valida.Validation. No se pueden validar los datos asignados a los campos.You cannot validate the data assigned to fields.

  • Inmutabilidad.Immutability. Visual Basic tuplas son mutables.Visual Basic tuples are mutable. En cambio, una estructura personalizada le permite controlar si una instancia es modificable o inmutable.In contrast, a custom structure allows you to control whether an instance is mutable or immutable.

Si los miembros personalizados, la validación de propiedades y campos o la inmutabilidad son importantes, debe utilizar la instrucción Visual Basic Structure para definir un tipo de valor personalizado.If custom members, property and field validation, or immutability are important, you should use the Visual Basic Structure statement to define a custom value type.

Una tupla Visual Basic hereda los miembros de su tipo ValueTuple .A Visual Basic tuple does inherit the members of its ValueTuple type. Además de sus campos, se incluyen los siguientes métodos:In addition to its fields, these include the following methods:

MiembroMember DescripciónDescription
CompareToCompareTo Compara la tupla actual con otra tupla con el mismo número de elementos.Compares the current tuple to another tuple with the same number of elements.
Es igual aEquals Determina si la tupla actual es igual a otra tupla u objeto.Determines whether the current tuple is equal to another tuple or object.
GetHashCodeGetHashCode Calcula el código hash de la instancia actual.Calculates the hash code for the current instance.
ToStringToString Devuelve la representación de cadena de esta tupla, que toma la forma (Item1, Item2...), donde Item1 y Item2 representan los valores de los campos de la tupla.Returns the string representation of this tuple, which takes the form (Item1, Item2...), where Item1 and Item2 represent the values of the tuple's fields.

Además, los tipos de ValueTuple implementan interfaces IStructuralComparable y IStructuralEquatable, que permiten definir comparadores de clientes.In addition, the ValueTuple types implement IStructuralComparable and IStructuralEquatable interfaces, which allow you to define customer comparers.

Asignación y tuplasAssignment and tuples

Visual Basic admite la asignación entre tipos de tupla que tienen el mismo número de campos.Visual Basic supports assignment between tuple types that have the same number of fields. Los tipos de campo se pueden convertir si se cumple una de las siguientes condiciones:The field types can be converted if one of the following is true:

  • El campo de origen y de destino son del mismo tipo.The source and target field are of the same type.

  • Se define una conversión de ampliación (o implícita) del tipo de origen al tipo de destino.A widening (or implicit) conversion of the source type to the target type is defined.

  • Option Strict es On y se define una conversión de restricción (o explícita) del tipo de origen al tipo de destino.Option Strict is On, and a narrowing (or explicit) conversion of the source type to the target type is defined. Esta conversión puede producir una excepción si el valor de origen está fuera del intervalo del tipo de destino.This conversion can throw an exception if the source value is outside the range of the target type.

Otras conversiones no se tienen en cuenta para las asignaciones.Other conversions are not considered for assignments. Echemos un vistazo a los tipos de asignaciones que se permiten entre los tipos de tupla.Let's look at the kinds of assignments that are allowed between tuple types.

Tenga en cuenta estas variables que se usan en los ejemplos siguientes:Consider these variables used in the following examples:

' 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 anonymous, no tienen nombres semánticos proporcionados para los campos.The first two variables, unnamed and anonymous, do not have semantic names provided for the fields. Los nombres de campo son los Item1 predeterminados y Item2.Their field names are the default Item1 and Item2. Las dos últimas variables, named y differentName tienen nombres de campo semánticos.The last two variables, named and differentName have semantic field names. Tenga en cuenta que estas dos tuplas tienen nombres diferentes para los campos.Note that these two tuples have different names for the fields.

Las cuatro de estas tuplas tienen el mismo número de campos (denominado "aridad") y los tipos de esos campos son idénticos.All four of these tuples have the same number of fields (referred to as 'arity'), and the types of those fields are identical. Por consiguiente, todas estas asignaciones funcionan:Therefore, all of these assignments work:

' 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.Notice that the names of the tuples are not assigned. Los valores de los campos se asignan según el orden de los campos de la tupla.The values of the fields are assigned following the order of the fields in the tuple.

Por último, observe que podemos asignar la tupla named a la tupla conversion, aunque el primer campo de la named sea un Integer y el primer campo de conversion sea una Long.Finally, notice that we can assign the named tuple to the conversion tuple, even though the first field of named is an Integer, and the first field of conversion is a Long. Esta asignación se realiza correctamente porque la conversión de un Integer en un Long es una conversión de ampliación.This assignment succeeds because converting an Integer to a Long is a widening conversion.

' 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)

Las tuplas con distintos números de campos no son asignables:Tuples with different numbers of fields are not assignable:

' 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étodoTuples as method return values

Un método solo puede devolver un valor.A method can return only a single value. Sin embargo, a menudo le gustaría que una llamada al método devuelva varios valores.Frequently, though, you'd like a method call to return multiple values. Hay varias maneras de solucionar esta limitación:There are several ways to work around this limitation:

  • Puede crear una clase o estructura personalizada cuyas propiedades o campos representen los valores devueltos por el método.You can create a custom class or structure whose properties or fields represent values returned by the method. Por lo tanto, es una solución pesada; requiere que se defina un tipo personalizado cuyo único propósito sea recuperar valores de una llamada al método.Thus is a heavyweight solution; it requires that you define a custom type whose only purpose is to retrieve values from a method call.

  • Puede devolver un valor único desde el método y devolver los valores restantes pasándolos por referencia al método.You can return a single value from the method, and return the remaining values by passing them by reference to the method. Esto implica la sobrecarga de crear instancias de una variable y los riesgos que sobrescriben involuntariamente el valor de la variable que se pasa por referencia.This involves the overhead of instantiating a variable and risks inadvertently overwriting the value of the variable that you pass by reference.

  • Puede usar una tupla, que proporciona una solución ligera para recuperar varios valores devueltos.You can use a tuple, which provides a lightweight solution to retrieving multiple return values.

Por ejemplo, los métodos TryParse en .net devuelven un valor Boolean que indica si la operación de análisis se realizó correctamente.For example, the TryParse methods in .NET return a Boolean value that indicates whether the parsing operation succeeded. El resultado de la operación de análisis se devuelve en una variable que se pasa por referencia al método.The result of the parsing operation is returned in a variable passed by reference to the method. Normalmente, una llamada a un método de análisis como Int32.TryParse tiene un aspecto similar al siguiente:Normally, a call to the a parsing method such as Int32.TryParse looks like the following:

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 a partir de la operación de análisis si encapsulamos la llamada al método Int32.TryParse en nuestro propio método.We can return a tuple from the parsing operation if we wrap the call to the Int32.TryParse method in our own method. En el ejemplo siguiente, NumericLibrary.ParseInteger llama al método Int32.TryParse y devuelve una tupla con nombre con dos elementos.In the following example, NumericLibrary.ParseInteger calls the Int32.TryParse method and returns a named tuple with two elements.

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

Después, puede llamar al método con código como el siguiente:You can then call the method with code like the following:

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 FrameworkVisual Basic tuples and tuples in the .NET Framework

Una tupla Visual Basic es una instancia de uno de los tipos genéricos System. ValueTuple , que se introdujeron en el .NET Framework 4,7.A Visual Basic tuple is an instance of one of the System.ValueTuple generic types, which were introduced in the .NET Framework 4.7. El .NET Framework también incluye un conjunto de clases genéricas System. Tuple .The .NET Framework also includes a set of generic System.Tuple classes. Sin embargo, estas clases difieren de las tuplas Visual Basic y los tipos genéricos System. ValueTuple de varias maneras:These classes, however, differ from Visual Basic tuples and the System.ValueTuple generic types in a number of ways:

  • Los elementos de las clases de tupla son propiedades denominadas Item1, Item2, etc.The elements of the Tuple classes are properties named Item1, Item2, and so on. En Visual Basic tuplas y los tipos ValueTuple , los elementos de tupla son campos.In Visual Basic tuples and the ValueTuple types, tuple elements are fields.

  • No se pueden asignar nombres descriptivos a los elementos de una instancia de tupla o de una instancia de ValueTuple .You cannot assign meaningful names to the elements of a Tuple instance or of a ValueTuple instance. Visual Basic permite asignar nombres que comunican el significado de los campos.Visual Basic allows you to assign names that communicate the meaning of the fields.

  • Las propiedades de una instancia de tupla son de solo lectura; las tuplas son inmutables.The properties of a Tuple instance are read-only; the tuples are immutable. En Visual Basic tuplas y los tipos ValueTuple , los campos de tupla son de lectura y escritura. las tuplas son mutables.In Visual Basic tuples and the ValueTuple types, tuple fields are read-write; the tuples are mutable.

  • Los tipos de tupla genéricos son tipos de referencia.The generic Tuple types are reference types. El uso de estos tipos de tupla implica la asignación de objetos.Using these Tuple types means allocating objects. En rutas de acceso activas, esto puede suponer un importante impacto en el rendimiento de la aplicación.On hot paths, this can have a measurable impact on your application's performance. Visual Basic tuplas y los tipos ValueTuple son tipos de valor.Visual Basic tuples and the ValueTuple types are value types.

Los métodos de extensión de la clase TupleExtensions facilitan la conversión entre Visual Basic tuplas y objetos de tupla de .net.Extension methods in the TupleExtensions class make it easy to convert between Visual Basic tuples and .NET Tuple objects. 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.The ToTuple method converts a Visual Basic tuple to a .NET Tuple object, and the ToValueTuple method converts a .NET Tuple object to a Visual Basic tuple.

En el ejemplo siguiente se crea una tupla, se convierte en un objeto de tupla de .net y se vuelve a convertir en una tupla Visual Basic.The following example creates a tuple, converts it to a .NET Tuple object, and converts it back to a Visual Basic tuple. A continuación, en el ejemplo se compara esta tupla con la original para asegurarse de que son iguales.The example then compares this tuple with the original one to ensure that they are equal.

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

Vea tambiénSee also