Genéricos
Los genéricos en C# son un componente fundamental del lenguaje que permite crear clases, métodos y estructuras capaces de operar con distintos tipos de datos sin perder la seguridad de tipos en tiempo de compilación. Su uso mejora la reutilización del código, aumenta la legibilidad y minimiza errores derivados de conversiones de tipos. Son especialmente útiles al trabajar con colecciones como List
Se utilizan genéricos cuando necesitamos que un mismo bloque de código funcione con diferentes tipos de datos, manteniendo al mismo tiempo la coherencia y la seguridad de tipos. Están estrechamente relacionados con los principios de la programación orientada a objetos como encapsulación, polimorfismo y abstracción, facilitando la construcción de arquitecturas modulares y eficientes.
En este tutorial aprenderás a definir clases y métodos genéricos, aplicar restricciones de tipos (constraints), integrar genéricos en proyectos reales de C#, optimizar su rendimiento y evitar errores comunes como pérdidas de memoria o excepciones inesperadas.
Ejemplo Básico
textusing System;
namespace GenericsDemo
{
// Definición de una clase genérica simple
public class Caja<T>
{
private T contenido;
public void Agregar(T item)
{
contenido = item;
}
public T Obtener()
{
return contenido;
}
}
class Program
{
static void Main(string[] args)
{
// Uso de la clase genérica con int
Caja<int> cajaInt = new Caja<int>();
cajaInt.Agregar(42);
Console.WriteLine("Contenido de la caja: " + cajaInt.Obtener());
// Uso de la clase genérica con string
Caja<string> cajaString = new Caja<string>();
cajaString.Agregar("Hola mundo");
Console.WriteLine("Contenido de la caja: " + cajaString.Obtener());
}
}
}
En este ejemplo, la clase Caja
Los genéricos proporcionan seguridad de tipos en tiempo de compilación, evitando errores por conversiones y promoviendo la reutilización de código. Esto sigue los principios de OOP y las mejores prácticas de C#, permitiendo crear aplicaciones seguras, legibles y mantenibles.
Ejemplo Práctico
textusing System;
using System.Collections.Generic;
namespace AdvancedGenericsDemo
{
// Repositorio genérico con restricción de tipo
public class Repositorio<T> where T : class
{
private List<T> items = new List<T>();
public void Agregar(T item)
{
if (item == null)
throw new ArgumentNullException(nameof(item), "El elemento no puede ser null");
items.Add(item);
}
public T Buscar(Predicate<T> predicado)
{
return items.Find(predicado);
}
public void MostrarTodos()
{
foreach (var item in items)
{
Console.WriteLine(item.ToString());
}
}
}
class Producto
{
public string Nombre { get; set; }
public decimal Precio { get; set; }
public override string ToString()
{
return $"{Nombre} - {Precio} USD";
}
}
class Program
{
static void Main(string[] args)
{
Repositorio<Producto> repoProductos = new Repositorio<Producto>();
repoProductos.Agregar(new Producto { Nombre = "Laptop", Precio = 1200 });
repoProductos.Agregar(new Producto { Nombre = "Smartphone", Precio = 800 });
Console.WriteLine("Todos los productos:");
repoProductos.MostrarTodos();
Producto productoCaro = repoProductos.Buscar(p => p.Precio > 1000);
Console.WriteLine("Producto caro: " + productoCaro);
}
}
}
El ejemplo avanzado muestra la clase genérica Repositoriowhere T : class
, asegurando que solo se puedan usar tipos de referencia. El método Agregar valida que el elemento no sea null, evitando errores de ejecución. Buscar utiliza Predicate
La clase Producto representa un caso real, con un método ToString sobrescrito para una presentación clara. Este ejemplo integra genéricos con OOP, manejo de excepciones y algoritmos, siguiendo buenas prácticas de C# y patrones de diseño.
Buenas prácticas y errores comunes con genéricos en C#:
- Utiliza constraints para garantizar la seguridad de tipos.
- Evita almacenar recursos no administrados directamente en clases genéricas.
- Prefiere colecciones genéricas incorporadas como List
y Dictionary\ . - Valida los valores null y maneja excepciones correctamente.
- No abuses de la generalización para evitar código complejo.
- Comprueba los tipos reales durante la depuración.
- Evita boxing/unboxing innecesario para optimizar rendimiento.
- Asegura la integridad de datos y la validación de entradas.
📊 Tabla de Referencia
C# Element/Concept | Description | Usage Example |
---|---|---|
Clase genérica | Clase que puede trabajar con distintos tipos | public class Caja<T> { T contenido; } |
Método genérico | Método que funciona con varios tipos de datos | public T ObtenerItem<T>(T item) { return item; } |
Constraints | Restricciones para los tipos | where T : class, new() |
List<T> | Colección genérica de elementos | List<int> numeros = new List<int>(); |
Dictionary\<TKey,TValue> | Colección genérica clave-valor | Dictionary\<string,int> edades = new Dictionary\<string,int>(); |
Predicate<T> | Delegado para búsqueda y filtrado | items.Find(p => p.Precio > 1000); |
Resumen y próximos pasos:
Los genéricos en C# permiten crear código seguro, reutilizable y eficiente. Con clases y métodos genéricos, restricciones de tipos y patrones de diseño, puedes construir arquitecturas modulares con alto rendimiento y menor riesgo de errores en tiempo de ejecución.
Se recomienda explorar Stack
🧠 Pon a Prueba tu Conocimiento
Prueba tu Conocimiento
Pon a prueba tu comprensión de este tema con preguntas prácticas.
📝 Instrucciones
- Lee cada pregunta cuidadosamente
- Selecciona la mejor respuesta para cada pregunta
- Puedes repetir el quiz tantas veces como quieras
- Tu progreso se mostrará en la parte superior