Generics en C#: para qué sirven y cómo usarlos para principiantes

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

Qué son los Generics en C# y para qué sirven



Imagina que escribes un método que debe funcionar con diferentes tipos de datos: números enteros, cadenas, objetos. Sin Generics (genéricos), tendrías que duplicar el código para cada tipo o usar object con la posterior conversión de tipos. Ambos enfoques generan problemas: el primero conduce a redundancia, el segundo a errores en tiempo de ejecución.



Los Generics (tipos genéricos) son un mecanismo en C# que permite crear clases, métodos, interfaces y delegados que funcionan con cualquier tipo de datos, manteniendo al mismo tiempo una tipificación estricta. En lugar de escribir código para un tipo específico, usas un parámetro de tipo (generalmente denotado con la letra T), que se reemplaza por el tipo real al usarlo.



Principales ventajas de los Generics:



  • Seguridad de tipos — el compilador verifica la corrección del uso de tipos en tiempo de compilación
  • Rendimiento — ausencia de boxing/unboxing para tipos de valor
  • Reutilización de código — una clase/método funciona con múltiples tipos
  • Legibilidad — el código se vuelve más limpio y comprensible


El problema sin Generics: ejemplo con object



Antes de la aparición de los Generics, los desarrolladores solían usar el tipo object para crear métodos universales. Veamos un ejemplo:



public class Stack{    private object[] _items = new object[10];    private int _count = 0;        public void Push(object item) { _items[_count++] = item; }    public object Pop() { return _items[--_count]; }        // Uso    Stack stack = new Stack();    stack.Push(123);           // Boxing de int a object    stack.Push("hello");       // Se puede agregar cualquier tipo    int number = (int)stack.Pop(); // Unboxing y conversión}


Los problemas son evidentes:

  • Al extraer se necesita una conversión explícita de tipo
  • Se puede agregar accidentalmente un valor de otro tipo
  • Para tipos de valor (int, double) ocurre boxing/unboxing, lo que reduce el rendimiento


Fundamentos del trabajo con Generics en C#



Creación de una clase genérica



Veamos el mismo ejemplo de la pila, pero usando Generics:



public class Stack<T>{    private T[] _items = new T[10];    private int _count = 0;        public void Push(T item) { _items[_count++] = item; }    public T Pop() { return _items[--_count]; }}

// UsoStack<int> intStack = new Stack<int>();intStack.Push(123);intStack.Push(456);int number = intStack.Pop(); // No se necesita unboxing, el tipo es conocido

Stack<string> stringStack = new Stack<string>();stringStack.Push("Hello");// stringStack.Push(123); // ¡Error de compilación! Seguridad de tipos


El parámetro <T> se indica entre corchetes angulares. Al crear una instancia, especificas el tipo concreto, y el compilador genera una versión especializada de la clase para ese tipo.



Métodos genéricos



Los Generics no solo funcionan con clases, sino también con métodos individuales:



public class Utils{    public static T Max<T>(T a, T b) where T : IComparable<T>    {        return a.CompareTo(b) > 0 ? a : b;    }}

// Usoint maxInt = Utils.Max(5, 10); // 10string maxStr = Utils.Max("apple", "banana"); // "banana"


Restricciones (Constraints) en Generics



A veces es necesario restringir los tipos que se pueden usar con un genérico. Para ello se utilizan restricciones (constraints) con la palabra clave where:



// Restricción: T debe ser un tipo de referenciapublic class Repository<T> where T : class{                

Blogs

Book Recommendations