Menu
Coddy logo textTech

Genéricos (clases y métodos)

Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy — lección 42 de 70.

Los genéricos le permiten escribir clases y métodos que funcionan con cualquier tipo de datos manteniendo la seguridad de tipos. En lugar de escribir clases separadas para IntList, StringList y DoubleList, usted escribe una clase genérica que los maneja a todos.

Una clase genérica utiliza un parámetro de tipo, normalmente llamado T, encerrado entre corchetes angulares:

public class Box<T>
{
    private T content;
    
    public void Store(T item) => content = item;
    public T Retrieve() => content;
}

// Uso con diferentes tipos
Box<int> intBox = new Box<int>();
intBox.Store(42);

Box<string> stringBox = new Box<string>();
stringBox.Store("Hello");

Cuando creas Box<int>, el compilador reemplaza cada T con int. Esto proporciona comprobación de tipos en tiempo de compilación: no puedes almacenar accidentalmente una cadena en una caja int.

Los métodos genéricos funcionan de manera similar, permitiendo que un solo método opere con diferentes tipos:

public static void Swap<T>(ref T a, ref T b)
{
    T temp = a;
    a = b;
    b = temp;
}

int x = 1, y = 2;
Swap(ref x, ref y);  // x=2, y=1

El compilador infiere el tipo a partir de los argumentos, por lo que no es necesario escribir Swap<int> explícitamente. Los genéricos son la base de colecciones como List<T> y Dictionary<TKey, TValue>, lo que permite un código reutilizable y seguro en cuanto a tipos.

challenge icon

Desafío

Fácil

Vamos a construir un sistema genérico Storage<T> que pueda contener y gestionar elementos de cualquier tipo. Crearás una clase contenedora reutilizable que demuestra el poder de los genéricos: ¡escríbela una vez y úsala con enteros, cadenas o cualquier otro tipo!

Organizarás tu código en dos archivos:

  • Storage.cs: Crea una clase genérica Storage<T> en el espacio de nombres DataStorage. Tu contenedor de almacenamiento debe:
    • Tener un array privado de tipo T para contener los elementos y una propiedad Count que rastree cuántos elementos hay almacenados
    • Aceptar una capacidad en su constructor para inicializar el array interno
    • Tener un método Add(T item) que añada un elemento si hay espacio
    • Tener un método Get(int index) que devuelva el elemento en el índice especificado
    • Tener un método GetAll() que devuelva todos los elementos almacenados unidos por ", "
  • Program.cs: En tu archivo principal, demuestra que tu clase genérica funciona con dos tipos diferentes. Crea un Storage<int> y un Storage<string>, añade elementos a cada uno y muestra que la misma clase funciona perfectamente con ambos tipos.

Recibirás cuatro entradas:

  • Primer entero a almacenar
  • Segundo entero a almacenar
  • Primera cadena a almacenar
  • Segunda cadena a almacenar

Crea un almacenamiento de enteros con capacidad 5 y un almacenamiento de cadenas con capacidad 5. Añade los dos enteros al almacenamiento de enteros y las dos cadenas al almacenamiento de cadenas.

Imprime la salida en este formato:

Int storage: {GetAll()}
Int count: {Count}
First int: {Get(0)}
String storage: {GetAll()}
String count: {Count}
First string: {Get(0)}

Por ejemplo, si las entradas son 42, 100, Hello, y World, la salida debería ser:

Int storage: 42, 100
Int count: 2
First int: 42
String storage: Hello, World
String count: 2
First string: Hello

Observa cómo escribes la clase Storage<T> una sola vez, pero funciona perfectamente tanto con int como con string: ¡esa es la magia de los genéricos! El compilador garantiza la seguridad de tipos, por lo que no puedes añadir accidentalmente una cadena a tu almacenamiento de enteros.

Hoja de referencia

Los genéricos le permiten escribir clases y métodos que funcionan con cualquier tipo de datos manteniendo la seguridad de tipos.

Una clase genérica utiliza un parámetro de tipo (normalmente T) encerrado entre paréntesis angulares:

public class Box<T>
{
    private T content;
    
    public void Store(T item) => content = item;
    public T Retrieve() => content;
}

Al crear una instancia, especifique el tipo para reemplazar a T:

Box<int> intBox = new Box<int>();
intBox.Store(42);

Box<string> stringBox = new Box<string>();
stringBox.Store("Hello");

Los métodos genéricos permiten que un solo método opere con diferentes tipos:

public static void Swap<T>(ref T a, ref T b)
{
    T temp = a;
    a = b;
    b = temp;
}

int x = 1, y = 2;
Swap(ref x, ref y);  // Compiler infers type from arguments

Los genéricos proporcionan comprobación de tipos en tiempo de compilación y son la base de colecciones como List<T> y Dictionary<TKey, TValue>.

Pruébalo tú mismo

using System;
using DataStorage;

class Program
{
    public static void Main(string[] args)
    {
        // Leer entradas
        int num1 = Convert.ToInt32(Console.ReadLine());
        int num2 = Convert.ToInt32(Console.ReadLine());
        string str1 = Console.ReadLine();
        string str2 = Console.ReadLine();

        // TODO: Crear un Storage<int> con capacidad 5
        
        // TODO: Agregar los dos enteros al almacenamiento de enteros
        
        // TODO: Crear un Storage<string> con capacidad 5
        
        // TODO: Agregar las dos cadenas al almacenamiento de cadenas
        
        // TODO: Imprimir la salida en el formato requerido
        // Almacenamiento de enteros: {GetAll()}
        // Cantidad de enteros: {Count}
        // Primer entero: {Get(0)}
        // Almacenamiento de cadenas: {GetAll()}
        // Cantidad de cadenas: {Count}
        // Primera cadena: {Get(0)}
    }
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos