Tabla de Contenido
0. Introducción1. Problema
2. Solución
3. Discusión de la Solución
3.1 ¿Cómo declarar un tipo genérico?
3.2 Ejemplo de lista genérica
3.3 Consideraciones adicionales acerca del uso de genéricos
3.4 Uso de la clausula where
4. Práctica: Código Fuente C#
5. Conclusiones
6. Glosario
7. Enlaces & Literatura
0. Introducción
En la receta previa -Uso de una Colección con Tipos de Datos Específicos- vimos que es posible crear instancias de una estructura de datos (e.g., List<T>, Queue<T>, Dictionary<TKey, TValue>, Stack<T>) especificando un tipo de dato concreto a almacenar dentro la estructura. Ahora que ya tenemos una idea básica o fundamental de genéricos en C#, vamos a desarrollar esta receta enfocada a la creación de un tipo genérico (clase, estructura, o interfaz). ¡Manos a la obra!
1. Problema
Una de las soluciones software de nuestra aplicación, a pesar de que funciona correctamente, merece una actualización. El departamento de desarrollo ha encargado a la división de soluciones informáticas para PYMES, hacer un mantenimiento y actualización a esta aplicación y adaptarla a los cambios surgidos a partir de la versión 2.0 del Framework .NET de Microsoft.
2. Solución
A partir de la versión 2.0 del Framework .NET ya es posible programar tipos genéricos en el lenguaje de programación C#. A partir de la definición tipos genéricos podemos aprovechar para actualizar (refactorizar) varios de los tipos de la aplicación para mejorar su desempeño: mayor consistencia y con menor riesgo de generación de errores en el tratamiento de tipos en estructuras de datos o tipos genéricos.
3. Discusión de la Solución
Ya en la receta anterior vimos que varias de las estructuras de datos en el namespace System.Collections.Generic (e.g., List<T>, Queue<T>, Dictionary<TKey, TValue>, Stack<T>). Esta característica brinda al programador cierta rigurosidad en la manipulación de los tipos a almacenar en la estructura. Este concepto de tratamiento es conocido (en inglés) como: strongly typed.
El concepto de strongly typed consiste en el tratamiento (agregación, remoción, actualización, lectura) seguro.
3.1 ¿Cómo declarar un tipo genérico?
Procedamos a conocer la sintaxis en C# para crear tipos genéricos. Empecemos por la definición de una clase:public class TipoGenerico<T [,{...}]>
(La notación [,{...}] para señalar que TipoGenerico puede contener uno más parámetros de tipo)
Al parámetro de tipo T también lo podríamos llamar parámetro génerico de tipo. Tracionalmente se ha utilizado la letra T para referirnos a un parámetro de tipo, y esa tradición empezó con la introducción de las plantillas (templates [4]) en el lenguaje de programación C++.
Ahora echemos un vistazo a la especificación de una de las estructuras de datos definidas en System.Collections.Generic:
Clase IDictionary<TKey, TValue> [5]:
public class Dictionary
Se hace evidente el uso múltiple de parámetro de tipo. En este caso tenemos dos: TKey, y TValue.
3.2 Ejemplo de lista genérica
Veamos este breve ejemplo de creación de una clase -ListaGenerica<T>- para una lista genérica:
public class ListaGenerica<T>
{
void Agregar(T elemento)
{
// Implementación
}
}
public class PruebaListaGenerica
{
public static void Main()
{
// Creación de lista genérica con tipos string:
ListaGenerica<string> listaCadenas = new ListaGenerica<string>();
// Creación de lista genérica con tipos double:
ListaGenerica<double> listaDouble = new ListaGenerica<double>();
// Creación de lista genérica con tipos Button:
ListaGenerica<Button> listaBotones = new ListaGenerica<Button>();
}
}
En el código cliente de la clase PruebaListaGenerica podemos observar que nuestra lista genérica admite diferente tipos de datos (en particular: string, double, y Button). En tiempo de ejecución, el tratamiento de la lista estará acotado a tratar sólo con ese tipo de dato particular, cualquier intento de agregar un tipo no admisible, generará la excepción System.InvalidCastException [4]. Debo aclarar que la CLR (Common Language Runtime), en tiempo de ejecución (valga el pleonasmo), tratará de convertir implícitamente el tipo pasado como parámetro de tipo.
3.3 Consideraciones adicionales acerca del uso de genéricos
Vale tener en cuenta las especificaciones acerca del uso de genéricos aportada por [1]:
- El parámetro de tipo puede ser un tipo por valor o un tipo referencia.
- Los tipos por referencia deben poseer un constructor con cero argumentos (vacío) para ascender el parámetro de tipo para el tipo.
- Se permite la jerarquía de herencia y de implementación para el parámetro de tipo.
3.4 Uso de la clausula where
Con la clausula where podemos establecer una restricción de jerarquía sobre el parámetro de tipo. Así:
public class NuevoTipoGenerico<T> where T : {Clase | Interfaz}
public class NuevoTipoGenerico<T> where T : {Clase | Interfaz}
T puede heredar (desde Clase) o implementar (a Interfaz). Los argumentos que se pasen al tipo genérico debe pertenecer o implementar a la jerarquía de herencia o de implementación.
4. Práctica: Código Fuente C#
El siguiente ejemplo consistirá en un tipo genérico representa a una bolsa que puede contener n cantidad de elementos (se admiten duplicados) sin orden alguno (desordenados), y éstos independientes del tipo.
Archivo Bolsa.cs:
[Nota: Omito explicación de código fuente debido a que éste posee documentación.]
Compilación:
- csc /target:exe Bolsa.cs
> Prueba de ejecución.
Resultado (puede variar dado que el contenido de la bolsa se extrae de forma aleatoria):
Contenido de la bolsa:
Elemento: DotNET Elemento: Microsoft Elemento: C# Elemento: Language Elemento: CLR Elemento: Framework Extracción de elementos: Elemento removido: Framework Elemento removido: Microsoft Elemento removido: C# Contenido actual de la bolsa: Elemento: DotNET Elemento: Language Elemento: CLR Removiendo todos los elementos de la bolsa: Contenido actual de la bolsa:
5. Conclusiones
Vimos a través de recete varios de los conceptos de tipos genéricos. Creamos un tipo genérico (Bolsa) para demostrar varias operaciones comunes de los tipos de esta naturaleza. Vale decir una vez más que, los genéricos simplifican el desarrollo y recude los errores que pudieran ocurrir al tratar todos los elementos de una colección o arreglo como System.Object.
6. Glosario
- Actualización
- Aplicación
- CLR
- Colección
- Collection
- Genéric
- Mantenimiento
- Object
- Refactorización
7. Enlaces & Literatura
[1]: Visual C# 2010 Recipes by Allen Jones and Adam Freeman. Copyright 2010 Allen Jones and Adam Freeman, 978-1-4302-2525-6.[2]: Generics (C# Programming Guide) - http://msdn.microsoft.com/en-us/library/512aeb7t.aspx
[3]: Template (C++), the free encyclopedia - https://en.wikipedia.org/wiki/Template_%28C%2B%2B%29
[4]: ArgumentException Class (System) - http://msdn.microsoft.com/en-us/library/system.argumentexception%28v=vs.110%29.aspx
[5]: Dictionary(TKey, TValue) Class (System.Collections.Generic) - http://msdn.microsoft.com/en-us/library/xfhwa508%28v=vs.110%29.aspx
[6]: where clause (C# Reference) - http://msdn.microsoft.com/en-us/library/bb311043.aspx
M
No hay comentarios:
Publicar un comentario
Envíe sus comentarios, dudas, sugerencias, críticas. Gracias.