Ventajas de los genéricos (Guía de programación de C#)

Actualización: noviembre 2007

Los tipos genéricos proporcionan la solución a una limitación de las versiones anteriores de Common Language Runtime y del lenguaje C#, en los que se realiza una generalización mediante la conversión de tipos a y desde el tipo base universal Object. Con la creación de una clase genérica, se puede crear una colección que garantiza la seguridad de tipos en tiempo de compilación.

Las limitaciones del uso de clases de colección no genéricas se pueden demostrar escribiendo un breve programa que utilice la clase de colección ArrayList de la biblioteca de clases base de .NET Framework. ArrayList es una clase de colección muy conveniente, que se puede utilizar sin modificar para almacenar tipos de referencia o tipos de valor.

// The .NET Framework 1.1 way to create a list:
System.Collections.ArrayList list1 = new System.Collections.ArrayList();
list1.Add(3);
list1.Add(105);

System.Collections.ArrayList list2 = new System.Collections.ArrayList();
list2.Add("It is raining in Redmond.");
list2.Add("It is snowing in the mountains.");

Pero esta conveniencia tiene su costo. Cualquier referencia o tipo de valor agregado a un objeto ArrayList se convierte implícitamente a Object. Si los elementos son tipos de valor, se les debe aplicar la conversión boxing cuando se agregan a la lista y la conversión unboxing cuando se recuperan. Tanto las operaciones de conversión de tipos como las de conversiones boxing y unboxing reducen el rendimiento; el efecto de las conversiones boxing y unboxing puede ser muy notable en los casos en los que se deben recorrer en iteración colecciones extensas.

La otra limitación es la ausencia de comprobación de tipos en tiempo de compilación; dado que un objeto ArrayList convierte todo a Object, en tiempo de compilación no hay forma de evitar que el código de cliente haga cosas como la siguiente:

System.Collections.ArrayList list = new System.Collections.ArrayList();
// Add an integer to the list.
list.Add(3);
// Add a string to the list. This will compile, but may cause an error later.
list.Add("It is raining in Redmond.");

int t = 0;
// This causes an InvalidCastException to be returned.
foreach (int x in list)
{
    t += x;
}

Aunque es perfectamente válido y a veces intencionado si se crea una colección heterogénea, es probable que la combinación de cadenas y valores ints en un objeto ArrayList único sea un error de programación, el cual no se detectará hasta el tiempo de ejecución.

En las versiones 1.0 y 1.1 del lenguaje C#, se podían evitar los riesgos de utilizar código generalizado en las clases de colección de la biblioteca de clases base de .NET Framework escribiendo colecciones propias específicas del tipo. Claro está que, como dicha clase no se puede reutilizar para más de un tipo de datos, se pierden las ventajas de la generalización y se debe volver a escribir la clase para cada uno de los tipos que se van a almacenar.

Lo que ArrayList y otras clases similares realmente necesitan es un modo de que el código de cliente especifique, por instancias, el tipo de datos particular que se va a utilizar. Eso eliminaría la necesidad de convertir a T:System.Object y también haría posible que el compilador realizara la comprobación de tipos. Es decir, ArrayList necesita un parámetro de tipo. Eso es precisamente lo que los tipos genéricos proporcionan. En la colección genérica List<T>, en el espacio de nombres N:System.Collections.Generic, la misma operación de agregar elementos a la colección tiene la apariencia siguiente:

// The .NET Framework 2.0 way to create a list
List<int> list1 = new List<int>();

// No boxing, no casting:
list1.Add(3);

// Compile-time error:
// list1.Add("It is raining in Redmond.");

En el código de cliente, la única sintaxis que se agrega con List<T> en comparación con ArrayList es el argumento de tipo en la declaración y creación de instancias. A cambio de esta complejidad de codificación ligeramente mayor, se puede crear una lista que no sólo es más segura que ArrayList, sino que también es bastante más rápida, en especial cuando los elementos de lista son tipos de valor.

Vea también

Conceptos

Guía de programación de C#

Referencia

Introducción a los genéricos (Guía de programación de C#)

System.Collections.Generic

Conversión boxing y unboxing (Guía de programación de C#)

Otros recursos

Collections Best Practices