lunes, 28 de octubre de 2013

Generics (introducción)




Generics, es una de las mejoras más importantes introducidas en la versión 2.0 del .NET Framework y en Visual Studio 2005.

Los tipos genéricos agregan un concepto nuevo de parámetro, el parámetro de tipo, si indicado en C# mediante los símbolos de ‘<>’ y en la mayoría de los casos nombrados con la letra ‘T’, aunque esto no es relevante y podría nombrase con cualquier definición, de hecho para Entity Framework se suelen nombrar como ‘TEntity’, para claves primarias como ‘TKey’ y otros casos como ‘TValue’


Decir que dentro del CLR, la característica de genérico no solo está reservada para los métodos, ya que también pueden existir clases, estructuras, delegados, etc.



Recuerda que aquí tienes el indice de todos los posts del Curso de LinQ.

·         Generics

o   La palabra Reservada default(T)


Uno de los usos más frecuentes dentro de nuestras aplicaciones en .NET y sobre todo en tema actual al que nos enfrentamos LinQ, es el uso de colecciones en memoria, en las primeras versiones de .NET (1.0 y 1.1), todas las colecciones especiales guardaban datos del tipo base (object), por lo que tenían un rendimiento muy inferior y era mucho más sencillo que se produjera un error en tiempo de ejecución debido a los casting que había que hacer para poder usar alguno de sus elementos (boxing y unboxing). También existían los arrays, que aunque si tenían un tipo definido, estos tenían la limitación de una vez creados, no podían redimensionar sus elementos. Con la llegada de generics esto se arregló añadiendo versiones genéricas para prácticamente todas esas colecciones, introducidas en el espacio de nombres System.Collections.Generics.

Beneficio del uso de Generics:

  • Seguridad de tipos .- Cuando un algoritmo genérico es usado  con un tipo específico, el compilador se asegura de que el tipo de objeto utilizado sea compatible con el tipo de objeto precisado, indicando un error de compilación en caso negativo. No dejándonos ejecutar para lanzar este error en tiempo de ejecución como pasaba con las implementaciones no genéricas.
  • Código límpio .- El uso de generics, permite un código mucho más limpio y sin conversiones de tipos, haciendo que nuestro código sea menos numeroso y de más calidad.

  • Mejora de rendimiento .- Al no existir los procesos de boxing y unboxing, no hace falta realizar ningún movimiento de información de una parte a otra de la pila, ganando el tiempo de ejecución de los procesos. Esto lo veremos en más detalle en el la siguiente sección ‘problemas de usos de colecciones no genéricas’.

Bueno vamos a dejarnos de tanta literatura y vamos a ver el resultado en un ejemplo.

Queremos hacer una librería de métodos de ayuda para realizar acciones cotidianas, una de ella es cambiar valores, tan sencillo como recibir 2 parámetros e intercambiar los valores de uno a otro:

public class MisCaolculos
{

    public static void CambiarValores(ref int a, ref int b)
    {
        int _a = a;
        int _b = b;

        a = _b;
        b = _a;
    }

    public static void CambiarValores(ref double a, ref double b) { ... }

    public static void CambiarValores(ref decimal a, ref decimal b) { ... }

    public static void CambiarValores(ref long a, ref long b) { ... }

    public static void CambiarValores(ref DateTime a, ref DateTime b) { ... }

    /// ... y así con todos los tipos del CLR y los propios

}


Que decir de esta clase, que hubiera sido prácticamente imposible acabar con todos los métodos, ya que para que estuviera completa tendríamos que haber creado uno para cada uno de los tipos del CLR y de nuestras propias clases.


Como podemos observar es muy sencillo apreciar el patrón de cada uno de ellos, ya que todos reciben 2 parámetros del mismo tipo. En nuestra siguiente versión de la clase haremos uso de genérics y de sus parámetros de tipo para indicar como parámetro el tipo elegido para realizar la acción;

public static void CambiarValores<T>(ref T a, ref T b)
{
    T _a = a;
    T _b = b;

    a = _b;
    b = _a;
}


Si nos damos cuenta, con un único método hemos cubierto todos los posibles usos por cualquier tipo del CLR.

Los únicos cambios añadidos han sido la inclusión del tipo <T> y el tipo de los parámetros del mismo tipo del indicado en el parámetro de tipo, al igual que las variables auxiliares de dentro del método.


Pues con esto hemos acabado nuestro primer contacto general con generics y en la próxima entrega entraremos un poco más a fondo con los problemas que había antes de su aparición y porque es importante su uso.