Tipos genéricos en Visual Basic (Visual Basic)
Un tipo genérico es un único elemento de programación que se adapta para realizar la misma funcionalidad para varios tipos de datos. Al definir una clase o procedimiento genéricos, no es necesario definir una versión independiente para cada tipo de datos para el que quiera realizar esa funcionalidad.
Una analogía es un juego de destornilladores con puntas extraíbles. Inspecciona el tornillo y selecciona la punta adecuada (plana, de cruz o de estrella). Una vez insertada la cabeza correcta en el mango del destornillador, realizas la misma función con el destornillador, a saber, girar el tornillo.
Cuando se define un tipo genérico, se parametriza con uno o varios tipos de datos. Los parámetros de tipo permiten al código adaptar los tipos de datos a sus requisitos. El código puede declarar varios elementos de programación diferentes del elemento genérico, cada uno que actúa en un conjunto diferente de tipos de datos. Pero todos los elementos declarados realizan la lógica idéntica, independientemente de los tipos de datos que usen.
Por ejemplo, puede que quiera crear y usar una clase de cola que funcione en un tipo de datos específico, como String
. Puede declarar dicha clase desde System.Collections.Generic.Queue<T>, como se muestra en el ejemplo siguiente.
Public stringQ As New System.Collections.Generic.Queue(Of String)
Ahora puede usar stringQ
para trabajar exclusivamente con valores String
. Porque stringQ
es específico para String
en lugar de generalizarse para los valores de Object
, no hay enlace tardío ni conversión de tipo. Los tipos genéricos ahorran tiempo de ejecución y reducen los errores en tiempo de ejecución.
Para obtener más información sobre el uso de un tipo genérico, vea Cómo: Usar una clase genérica.
Ejemplo de una clase genérica
El siguiente ejemplo muestra una definición básica de una clase genérica.
Public Class classHolder(Of t)
Public Sub processNewItem(ByVal newItem As t)
Dim tempItem As t
' Insert code that processes an item of data type t.
End Sub
End Class
En el esqueleto anterior, t
es un parámetro de tipo , es decir, un marcador de posición para un tipo de datos que proporcione al declarar la clase. En otro lugar del código, puede declarar varias versiones de classHolder
proporcionando varios tipos de datos para t
. En el ejemplo siguiente se muestran dos declaraciones de este tipo.
Public integerClass As New classHolder(Of Integer)
Friend stringClass As New classHolder(Of String)
Las instrucciones anteriores declaran clases construidas, en las que un tipo específico reemplaza el parámetro de tipo. Este reemplazo se propaga a lo largo del código dentro de la clase construida. En el ejemplo siguiente se muestra el aspecto del procedimiento processNewItem
en integerClass
.
Public Sub processNewItem(ByVal newItem As Integer)
Dim tempItem As Integer
' Inserted code now processes an Integer item.
End Sub
Para obtener un ejemplo más completo, vea Cómo: Definir una clase que pueda proporcionar una funcionalidad idéntica en diferentes tipos de datos.
Elementos de programación aptos
Puede definir y usar clases, estructuras, interfaces, procedimientos y delegados genéricos. .NET define varias clases, estructuras e interfaces genéricas que representan elementos genéricos usados habitualmente. El espacio de nombres System.Collections.Generic proporciona diccionarios, listas, colas y pilas. Antes de definir su propio elemento genérico, consulte si ya está disponible en System.Collections.Generic.
Los procedimientos no son tipos, pero puede definir y usar procedimientos genéricos. Vea procedimientos genéricos de en Visual Basic.
Ventajas de los tipos genéricos
Un tipo genérico sirve como base para declarar varios elementos de programación diferentes, cada uno de los cuales funciona en un tipo de datos específico. Las alternativas a un tipo genérico son:
- Tipo único que opera en el tipo de dato
Object
. - Conjunto de versiones específicas del tipo. Cada versión se codifica individualmente y funciona en un tipo de datos específico, como
String
,Integer
o un tipo definido por el usuario, comocustomer
.
Un tipo genérico tiene las siguientes ventajas sobre estas alternativas:
- Seguridad de tipos. Los tipos genéricos fuerzan la comprobación de tipos en tiempo de compilación. Los tipos basados en
Object
aceptan cualquier tipo de datos y debe escribir código para comprobar si un tipo de datos de entrada es aceptable. Con los tipos genéricos, el compilador puede detectar errores de coincidencia de tipos antes del tiempo de ejecución. - Rendimiento. No es necesario que los tipos genéricos apliquen la conversión boxing y unboxing a los datos, ya que cada uno está diseñado para un tipo de datos. Las operaciones basadas en
Object
deben empacar los tipos de datos de entrada para convertirlos enObject
y desempacar los datos destinados a la salida. La conversión boxing y la conversión unboxing reducen el rendimiento. Los tipos basados enObject
también se enlazan en tiempo de ejecución, lo que significa que el acceso a sus miembros requiere código adicional en tiempo de ejecución. Las conversiones de tipos también reducen el rendimiento. - Consolidación del código. El código de un tipo genérico solo debe definirse una vez. Un conjunto de versiones específicas de tipo de un tipo debe replicar el mismo código en cada versión, siendo la única diferencia el tipo de datos específico para esa versión. Con los tipos genéricos, todas las versiones específicas del tipo se generan a partir del tipo genérico original.
- Reutilización de código. El código que no depende de un tipo de datos determinado se puede reutilizar con varios tipos de datos si es genérico. A menudo, puede volver a usarlo incluso con un tipo de datos que no predecía originalmente.
- Compatibilidad con IDE. Cuando se usa un tipo construido declarado a partir de un tipo genérico, el entorno de desarrollo integrado (IDE) puede proporcionarle más compatibilidad mientras desarrolla el código. Por ejemplo, IntelliSense puede mostrar las opciones específicas del tipo de un argumento para un constructor o método.
- Algoritmos genéricos. Los algoritmos abstractos independientes de tipos son buenos candidatos para tipos genéricos. Por ejemplo, un procedimiento genérico que ordena los elementos mediante la interfaz de IComparable se puede usar con cualquier tipo de datos que implemente IComparable.
Restricciones
Aunque el código de una definición de tipo genérico debe ser lo más independiente posible, es posible que tenga que requerir una determinada funcionalidad de cualquier tipo de datos proporcionado al tipo genérico. Por ejemplo, si desea comparar dos elementos para clasificar o agrupar, su tipo de datos debe implementar la interfaz IComparable. Puede aplicar este requisito agregando una restricción al parámetro type.
Ejemplo de una restricción
En el ejemplo siguiente se muestra una definición de esqueleto de una clase con una restricción que requiere el argumento type para implementar IComparable.
Public Class itemManager(Of t As IComparable)
' Insert code that defines class members.
End Class
Si el código posterior intenta construir una clase a partir de itemManager
proporcionar un tipo que no implementa IComparable, el compilador indica un error.
Tipos de restricciones
La restricción puede especificar los siguientes requisitos en cualquier combinación:
- El argumento type debe implementar una o varias interfaces.
- El argumento de tipo debe ser del tipo de una clase como máximo, o bien heredarse a lo sumo de una clase.
- El argumento type debe exponer un constructor sin parámetros accesible para el código que crea objetos a partir de él.
- El argumento de tipo debe ser un tipo de referencia , o debe ser un tipo de valor
El código de C# puede declarar que un argumento de tipo debe ser un tipo no administrado. Visual Basic aplica esta restricción para el código de Visual Basic que usa un tipo o método genérico que se definió con esta restricción (en C#). Sin embargo, no se puede declarar una restricción unmanaged
en un parámetro de tipo en Visual Basic.
Si necesita imponer más de un requisito, use una lista de restricción separada por comas entre llaves ({ }
). Para requerir un constructor accesible, incluya la palabra clave New Operator en la lista. Para requerir un tipo de referencia, incluya la palabra clave Class
; para requerir un tipo de valor, incluya la palabra clave Structure
.
Para obtener más información sobre las restricciones, vea Lista de tipos.
Ejemplo de varias restricciones
En el ejemplo siguiente se muestra una definición de esqueleto de una clase genérica con una lista de restricciones en el parámetro de tipo. En el código que crea una instancia de esta clase, el argumento type debe implementar las interfaces de IComparable y IDisposable, ser un tipo de referencia y exponer un constructor sin parámetros accesible.
Public Class thisClass(Of t As {IComparable, IDisposable, Class, New})
' Insert code that defines class members.
End Class
Términos importantes
Los tipos genéricos presentan y usan los siguientes términos:
- Tipo genérico. Definición de una clase, estructura, interfaz, procedimiento o delegado para el que se proporciona al menos un tipo de datos al declararlo.
- Parámetro de tipo. En una definición de tipo genérico, marcador de posición para un tipo de datos que proporciona al declarar el tipo.
- Argumento de tipo. Tipo de datos específico que reemplaza un parámetro de tipo al declarar un tipo construido a partir de un tipo genérico.
- Restricción. Condición en un parámetro de tipo que restringe el argumento de tipo que puede proporcionar para él. Una restricción puede requerir que el argumento de tipo implemente una interfaz determinada, herede de una clase determinada, tenga un constructor sin parámetros accesible o sea un tipo de referencia o un tipo de valor. Puede combinar estas restricciones, pero puede especificar como máximo una clase base.
- Tipo construido. Clase, estructura, interfaz, procedimiento o delegado declarado a partir de un tipo genérico proporcionando argumentos de tipo para sus parámetros de tipo.