Tipos · valor y referencia

struct frente a class en C#

El keyword importa menos que la semántica de asignación: una variable de class guarda una referencia a un objeto compartido; una de struct guarda su propia copia. Todo lo demás se deduce de ahí.

class: dos nombres, un objeto

Asignar una variable de clase copia la referencia, no el objeto. Ambos nombres apuntan a la misma caja:

class Perro
{
    public string Nombre;
    public Perro(string nombre) { Nombre = nombre; }
}

Perro a = new Perro("Rex");
Perro b = a;            // b es un SEGUNDO NOMBRE del mismo objeto
b.Nombre = "Max";       // renombrando a través de b…
Console.WriteLine(a.Nombre);   // …también se renombró para a
class Perro
{
    public string Nombre;
    public Perro(string nombre) { Nombre = nombre; }
}

Perro a = new Perro("Rex");
Perro b = new Perro("Rex");   // un objeto genuinamente nuevo y separado
b.Nombre = "Max";
Console.WriteLine(a.Nombre);      // intacto
Console.WriteLine(a == b);        // == compara REFERENCIAS: objetos distintos → False

struct: asignar es copiar

Los struct invierten la semántica. Asignar un struct copia el valor completo — las dos variables son independientes desde ese instante:

struct Punto
{
    public int X;
    public Punto(int x) { X = x; }
}

Punto a = new Punto(1);
Punto b = a;        // COPIA COMPLETA — b tiene su propio almacenamiento
b.X = 99;

Console.WriteLine(a.X);   // 1   — a nunca se tocó
Console.WriteLine(b.X);   // 99

Nota honesta: el motor del navegador trata hoy los struct como clases (semántica de referencia) — ese programa en Visual Studio imprime 1 y 99 como se muestra. El concepto se mantiene; verifica el copiado en un compilador real hasta que el motor tenga semántica de valor.

La trampa que esto explica

¿Te ha pasado que cambiaste un campo a través de una variable y otra variable "lo vio"? Eso era un alias de referencia. Y su espejo: cambiaste un campo de un struct dentro de un método y la copia del llamador no cambió. Ambas son el comportamiento correcto de su tipo — el bug es esperar el otro:

Escenarioclassstruct
b = a; copia…la referenciael valor completo
¿Mutar por b afecta a a?Sí — mismo objetoNo — copias separadas
a == b significa…misma identidadmismos valores (si == está definido)
Vive…en el heap, recolectadoen línea (pila o dentro de su dueño)

¿Cuál elegir?

La regla práctica que siguen casi todas las bases de código:

Autotest de un minuto

Ejecuta esto en el playground y predice la salida antes de pulsar Ejecutar — es la demo del alias con los nombres cambiados:

Perro x = new Perro("Uno");
Perro y = x;
y = new Perro("Dos");
Console.WriteLine(x.Nombre);   // predice: ¿Uno o Dos? (referencia vs objeto)

Si dijiste "Uno" — asignar new Perro("Dos") a y reapunta la referencia de y; nunca toca el objeto al que apunta x. Lectura relacionada: var frente a tipos explícitos.