Los genéricos en C# son una característica poderosa que permite definir clases, interfaces y métodos con un tipo de dato genérico. Esto proporciona una mayor flexibilidad y reutilización del código, ya que permite trabajar con cualquier tipo de dato sin necesidad de duplicar el código para cada tipo específico.
Conceptos Clave
- Definición de Genéricos: Permiten definir estructuras de datos y métodos que pueden operar con cualquier tipo de dato.
- Ventajas de los Genéricos:
- Reutilización del Código: Evita la duplicación de código.
- Seguridad de Tipo: Detecta errores de tipo en tiempo de compilación.
- Rendimiento: Elimina la necesidad de conversiones de tipo (boxing/unboxing).
Definición de Clases Genéricas
Una clase genérica se define utilizando un parámetro de tipo. Aquí hay un ejemplo de una clase genérica simple:
public class Caja<T>
{
private T contenido;
public void Guardar(T item)
{
contenido = item;
}
public T Obtener()
{
return contenido;
}
}Explicación del Código
public class Caja<T>: Define una clase genéricaCajacon un parámetro de tipoT.private T contenido;: Declara una variable de tipoT.public void Guardar(T item): Método que acepta un parámetro de tipoTy lo guarda encontenido.public T Obtener(): Método que devuelve el contenido de tipoT.
Uso de la Clase Genérica
Caja<int> cajaDeEnteros = new Caja<int>();
cajaDeEnteros.Guardar(123);
int numero = cajaDeEnteros.Obtener();
Caja<string> cajaDeCadenas = new Caja<string>();
cajaDeCadenas.Guardar("Hola Mundo");
string mensaje = cajaDeCadenas.Obtener();Métodos Genéricos
Los métodos genéricos permiten definir métodos con parámetros de tipo genérico. Aquí hay un ejemplo:
public class Utilidades
{
public static void Intercambiar<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
}Explicación del Código
public static void Intercambiar<T>(ref T a, ref T b): Define un método genéricoIntercambiarque intercambia los valores deayb.
Uso del Método Genérico
int x = 1, y = 2; Utilidades.Intercambiar(ref x, ref y); // Ahora x es 2 y y es 1 string s1 = "Hola", s2 = "Mundo"; Utilidades.Intercambiar(ref s1, ref s2); // Ahora s1 es "Mundo" y s2 es "Hola"
Restricciones de Tipo
Las restricciones de tipo permiten especificar los requisitos que debe cumplir un tipo genérico. Aquí hay un ejemplo:
public class Almacen<T> where T : IComparable
{
private T[] elementos;
private int indice;
public Almacen(int tamaño)
{
elementos = new T[tamaño];
indice = 0;
}
public void Agregar(T item)
{
if (indice < elementos.Length)
{
elementos[indice] = item;
indice++;
}
}
public T Obtener(int i)
{
return elementos[i];
}
}Explicación del Código
where T : IComparable: Restricción que indica queTdebe implementar la interfazIComparable.
Uso de la Clase con Restricciones
Almacen<int> almacenDeEnteros = new Almacen<int>(10); almacenDeEnteros.Agregar(5); int valor = almacenDeEnteros.Obtener(0);
Ejercicio Práctico
Ejercicio
Crea una clase genérica Pila<T> que implemente una pila (stack) con las siguientes operaciones:
Push(T item): Agrega un elemento a la pila.Pop(): Elimina y devuelve el elemento en la parte superior de la pila.Peek(): Devuelve el elemento en la parte superior de la pila sin eliminarlo.Count: Propiedad que devuelve el número de elementos en la pila.
Solución
public class Pila<T>
{
private List<T> elementos = new List<T>();
public void Push(T item)
{
elementos.Add(item);
}
public T Pop()
{
if (elementos.Count == 0)
throw new InvalidOperationException("La pila está vacía.");
T item = elementos[elementos.Count - 1];
elementos.RemoveAt(elementos.Count - 1);
return item;
}
public T Peek()
{
if (elementos.Count == 0)
throw new InvalidOperationException("La pila está vacía.");
return elementos[elementos.Count - 1];
}
public int Count
{
get { return elementos.Count; }
}
}Uso de la Clase Pila<T>
Pila<int> pilaDeEnteros = new Pila<int>(); pilaDeEnteros.Push(1); pilaDeEnteros.Push(2); pilaDeEnteros.Push(3); int cima = pilaDeEnteros.Peek(); // Devuelve 3 int elemento = pilaDeEnteros.Pop(); // Devuelve 3 y lo elimina de la pila int cuenta = pilaDeEnteros.Count; // Devuelve 2
Conclusión
Los genéricos en C# son una herramienta esencial para escribir código flexible, reutilizable y seguro. Permiten trabajar con cualquier tipo de dato sin sacrificar la seguridad de tipo ni el rendimiento. En esta lección, hemos cubierto la definición de clases y métodos genéricos, el uso de restricciones de tipo y hemos implementado una clase genérica Pila<T> como ejercicio práctico.
En el próximo tema, exploraremos las colecciones genéricas en C#, que son una extensión natural de los conceptos que hemos aprendido aquí.
Curso de Programación en C#
Módulo 1: Introducción a C#
- Introducción a C#
- Configuración del Entorno de Desarrollo
- Programa Hola Mundo
- Sintaxis y Estructura Básica
- Variables y Tipos de Datos
Módulo 2: Estructuras de Control
Módulo 3: Programación Orientada a Objetos
- Clases y Objetos
- Métodos
- Constructores y Destructores
- Herencia
- Polimorfismo
- Encapsulamiento
- Abstracción
Módulo 4: Conceptos Avanzados de C#
- Interfaces
- Delegados y Eventos
- Genéricos
- Colecciones
- LINQ (Consulta Integrada en el Lenguaje)
- Programación Asíncrona
Módulo 5: Trabajando con Datos
Módulo 6: Temas Avanzados
- Reflexión
- Atributos
- Programación Dinámica
- Gestión de Memoria y Recolección de Basura
- Multihilo y Programación Paralela
Módulo 7: Construcción de Aplicaciones
Módulo 8: Mejores Prácticas y Patrones de Diseño
- Estándares de Codificación y Mejores Prácticas
- Patrones de Diseño
- Pruebas Unitarias
- Revisión y Refactorización de Código
