Inicio > Cursos > C# > Records, Structs y Generics
C#POO en C#Lección 15 de 20

Records, Structs y Generics

Records (C# 9+) resuelven el problema de los "data objects": clases que solo tienen datos sin comportamiento complejo. Con una clase normal necesitas 20-30 líneas para constructor, propiedades, equals, hashcode y toString. Con un record escribes una sola línea: record Persona(string Nombre, int Edad).

La diferencia clave con clases: los records tienen igualdad por valor (dos records con los mismos datos son iguales), mientras que dos clases con los mismos datos son distintos objetos.

Los structs son tipos de valor (se copian en lugar de compartir referencia), ideales para datos pequeños e inmutables como coordenadas, colores o rangos de fecha. Los generics permiten escribir código reutilizable para cualquier tipo, como la clase Pila<T> que funciona con int, string o cualquier objeto.

Las constraints (where T : interfaz) permiten restringir qué tipos puede ser T, garantizando que tiene ciertos métodos disponibles dentro de la clase genérica.

// Record - inmutable, igualdad por valor
public record Punto(double X, double Y);
public record Persona(string Nombre, int Edad);

var p1 = new Punto(3.0, 4.0);
var p2 = new Punto(3.0, 4.0);
Console.WriteLine(p1 == p2); // true (igualdad por valor)

var p3 = p1 with { Y = 5.0 }; // Copia con modificación
Console.WriteLine(p1); // Punto { X = 3, Y = 4 }

// Struct - tipo valor (en pila)
public struct Color {
    public byte R, G, B;
    public Color(byte r, byte g, byte b) { R=r; G=g; B=b; }
    public static Color Rojo => new(255, 0, 0);
    public override string ToString() => $"rgb({R},{G},{B})";
}

var color = Color.Rojo;
var copia = color; // Se COPIA, no referencia

// Generics - código reutilizable para cualquier tipo
public class Pila<T> {
    private List<T> _items = new();
    
    public void Push(T item) => _items.Add(item);
    
    public T Pop() {
        if (_items.Count == 0)
            throw new InvalidOperationException("Pila vacía");
        var top = _items[^1];
        _items.RemoveAt(_items.Count - 1);
        return top;
    }
    
    public T Peek() => _items[^1];
    public int Count => _items.Count;
}

var pilaEnteros = new Pila<int>();
pilaEnteros.Push(1);
pilaEnteros.Push(2);
Console.WriteLine(pilaEnteros.Pop()); // 2

// Método genérico
public T Maximo<T>(T a, T b) where T : IComparable<T> {
    return a.CompareTo(b) >= 0 ? a : b;
}

Console.WriteLine(Maximo(3, 7));      // 7
Console.WriteLine(Maximo("Ana", "Bob")); // Bob
Consejo📦 Records son perfectos para DTOs (Data Transfer Objects), objetos de valor y datos de configuración. Usa clases para entidades con comportamiento.
← Clases Abstractas y SealedDelegates, Events y Lambdas →

Practica esta lección

Resuelve los ejercicios del curso de C# en la app, gratis y con corrección automática.

Empezar a practicar