Posteado por: fzapataramirez | Martes, octubre 7, 2008

Colecciones de datos en C#.NET (Parte V: Colecciones Genéricas)

A diferencia de las colecciones de datos tratadas en los post anteriores, las colecciones genéricas se encuentran en el namespace System.Collections.Generics ya que son colecciones con la misma funcionalidad que las colecciones no genéricas (las normales, las que están en el namespace System.Collections), con la diferencia que estas están orientadas a trabajar con un tipo de dato especifico.

Con un tipo de dato especifico?. Si así es, porque a diferencia de las colecciones no genéricas en las que se pueden agregar cualquier tipo de elementos y todos son convertidos a System.Object, en este tipo de colecciones solo es posible almacenar elementos de un tipo de dato específico.

Cuando comencé a leer sobre esta nueva característica ofrecida por el Framework 2.0, me preguntaba si el nombre verdaderamente correspondía a la definición de estas colecciones, ya que no entendía el porque llamarlas genéricas si solo era posible almacenar datos del mismo tipo. Por el contrario, parecían ser más genéricas las otras colecciones (las del namespace System.Collections) ya que me permitían almacenar cualquier tipo de dato.

Pero finalmente y después de leer varios artículos y códigos de ejemplo, comprendí el porque del nombre generics y espero poder transmitirlo en este post.

Definitivamente, una colección genérica solo puede almacenar datos de un tipo, pero dicho tipo de dato es definido por nosotros mismos al momento de declararla e instanciarla. Es decir, no hay una clase para diferenciar las colecciones que operan con enteros de las que operan con cadenas de texto ni de las que operan objetos de tipo Empleado (por ejemplo). Absolutamente todas están definidas en la misma clase, lo único que las diferencia es la manera en que se instancia y se declara cada una de ellas. Ese es el secreto del ser genérica. Para entender mejor el concepto de la colección genérica, veamos el siguiente ejemplo:

clip_image002

En el ejemplo se observa la implementación de la colección genérica List, que es la versión genérica del ArrayList tratado en un post anterior. Se puede deducir que la primera colección permitirá almacenar únicamente datos de tipo int, que la segunda almacenara solo cadenas de texto y que la última almacenara objetos de tipo TablaDatos, el cual es un tipo definido en una clase aparte. En las definición de las tres colecciones se utilizo la clase List, es decir, que hay una clase “genérica” capaz de trabajar con el tipo de dato que indiquemos al momento de inicializarla. (Realmente no es cualquier tipo de dato, sino los tipos de datos soportados por la clase).

La diferencia para inicializar una clase genérica de una clase no genérica, es que en la primera se debe utilizar una parámetro adicional después del nombre de la clase y entre los caracteres < y >. Este parámetro debe ser un tipo de datos, que indica el tipo de datos con el que la colección deberá operar.

Así como esta la colecciones List<T>, que es la versión genérica del ArrayList, también existen las colecciones genéricas Stack<T>, Queue<T> y Dictionary<T>, entre otras que son las versiones genéricas de las clases Snack, Queue y HashTable respectivamente.

Un ejemplo de la clase genérica de Stack seria:

clip_image004

Se puede ver como se define una pila en la que únicamente se pueden almacenar datos de tipo entero, lo cual me permite obtener datos de la colección y tratarlos directamente como enteros sin necesidad de hacer algún tipo de cast, lo cual no seria posible con las colecciones no genéricas ya que el elemento es almacenado como un System.Object.

El hecho de que las colecciones genéricas operen con un tipo de dato definido en el momento de su declaración, las hace mucho más eficientes, ya que evita tener que realizar boxing, unboxing y casting de objetos. Adicionalmente los desarrolladores, obtienen un mayor grado de control sobre la información almacenada en la colección ya que en caso de intentar ingresar un objeto de un tipo de dato diferente al establecido en la inicialización de la colección, se arroja una excepción.

Además de esta ventaja que nos brindan las colecciones genéricas, tenemos la posibilidad de crear nuestras propias clases y métodos genérico cuyo comportamiento estará ligado al tipo de dato que se utilice al utilizarlo tal y como sucede con las colecciones. Para lograr esto debemos hacer uso de los “type parameters”, los cuales permiten establecer un parámetro cuyo tipo se desconocerá hasta que se indique en la declaración.

Para comprender mejor el funcionamiento de los “type parameters” que nos permiten crear clases genéricas, he desarrollado una aplicación de muestra que consiste en una clase impresora “genérica”, que es capaz de almacenar en una cola, objetos de un tipo específico (del tipo que se define al momento de definir un objeto de esta clase). Adicionalmente expone un método “imprimir” que se encarga de imprimir en pantalla cada uno de los valores contenidos en la cola. A continuación presento los fragmentos principales del código.

clip_image006

En esta primera imagen, se observa como se ha definido una clase Impresora genérica. Note que en este caso se utiliza la letra T para representar el “type parameter”, sin embargo es posible utilizar cualquier letra o palabra. Mediante este parámetro estamos indicando que al momento de definir e instanciar un objeto de tipo Impresora, se debe pasar como parámetro entre < y > el tipo de datos con el que se desea trabajar.

En el constructor de esta clase, se puede ver como la Queue genérica que tiene la clase Impresora como atributo toma su mismo tipo de dato, es decir, si al crear la clase Impresora indicamos el tipo de dato int, la Queue también tomara el tipo de dato int.

clip_image008

En esta segunda imagen se observa una propiedad que retorna una cola genérica, pero el type parameter para indicar que es una Queue genérica es el mismo utilizado en nuestra clase Impresora, lo cual indica que retornara una Queue del tipo de dato utilizado en la clase.

Finalmente se observa el método imprimir, cuyo objetivo es indicar el tipo de Queue que se esta imprimiendo y además mostrar cada uno de los elementos que contiene.

Como paso final, para comprobar el funcionamiento de la clase Impresora, se crea un objeto de tipo Impresora de enteros, así:

clip_image010

Otra de las ventajas que nos brinda la utilización de Generics, es que los “type parameters” se traducen en tiempo de compilación, lo cual implica que es posible darnos cuenta en el momento que desarrollamos nuestra aplicación, el tipo de datos con el que se esta trabajando en cada instancia de la clase Impresora, como se ve a continuación:

clip_image012

Finalmente, se observa el resultado de la ejecución de la aplicación en consola:

clip_image014

En conclusión, debemos utilizar las colecciones genéricas tanto como sea posible en lugar de utilizar las colecciones no genéricas, ya que las primeras incrementan el rendimiento de la aplicación ya que evita un sin numero de casting, boxing y unboxing lo que permite realizar un mejor manejo de la memoria y procesamiento.

Además podemos crear propias clases y/o métodos genéricos para aumentar la flexibilidad y la posibilidad de reutilizar nuestro código.


Responses

  1. Hola!. Hace poco que empece con .Net, y arranque directamente con el Framework 2.0. Ya he realizado proyectos y utilizo mucho las listas genéricas.

    Ahora bien, estoy incursionando en las aplicaciones para moviles, lo primero que noto es que cuando programo un formulario, no se pueden utilizar las listas genericas. No se puede agregar el ‘using’ que si se agrega en win32 o asp. Si me ayudas al mail te debo una. Saludos y gracias .-

  2. Hola Diego.

    Pues la verdad me parece bien raro porque de hecho es una de las recomendaciones para trabajar con moviles, usar en la medida de lo posible colecciones genericas por cuestiones de rendimiento.

    Debes agregar la directiva
    using System.Collections.Generic;
    Si te sale algun error por favor cuentame cual es. Tambien mira en la carpeta References de tu proyecto si estan incluidas las librerias System, mscorlib, System.Windows.Forms y Microsoft.WidowsCeForms.

    Saludos

  3. He programado en Ajax, C, C++, Java, Builder C++, Delphi, Visual basic 6.0, ahora aprendo C#, creo que es un lenguaje muy rico en sus tipos, es sumamente facil y agradable manejarlo para mi, este post es bueno en cuanto informacion sobre el lenguaje, ya que los ejemplos son sumamente faciles de entender, de dominar, mi experiencia lo ve como algo facil de realizar….

    Saludos, desde MEXICO….

  4. Muchas gracias fzapataramirez… información muy valiosa explicada de forma simple

    saludos🙂

  5. Excelente articulo, explicado muy sencillo😉

  6. que va esta c
    interesante tu tutorial pero una cosa no tendras uno pero con windows from?

    • Cual seria la diferencia? Con winforms, webforms, servicios, silverlight y wpf se comportan de la misma manera

  7. He aprendido mas en estas 2 horas gracias a tu sabios consejos que en lo que pude haber aprendido en 2 años

    • Gracias amigo.

      Realmente me alegra saber que de algo sirven las publicaciones.

  8. Hola Amigo.
    por aquí buscando un poquitiño de información cai en tu blog y me parece estupendo como explicas es muy entendible y concreto con ejemplos claros.
    te felicito por ello.

    saludos.

    Magda


Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

Categorías

A %d blogueros les gusta esto: