Cuando trabajas con C#, las clases no son tu única herramienta. Existen otros dos tipos, struct y record, que resuelven escenarios muy puntuales donde una clase resulta excesiva o poco práctica. Entender la diferencia entre class, struct y record en C# te ayuda a decidir cuándo conviene comparar por referencia y cuándo por valor, algo clave en aplicaciones modernas como microservicios.
¿Qué diferencia hay entre clases, estructuras y registros en C#?
La distinción central está en cómo cada tipo maneja la identidad de los objetos y para qué tamaño de componente se diseñó.
Las clases son el tipo más versátil y trabajan por reference. Cada vez que instancias un objeto, C# reserva una posición de memoria y le asigna un identificador propio. Por eso, dos objetos con datos idénticos siguen siendo distintos: cada uno apunta a una referencia diferente. Las clases sirven para componentes pequeños, medianos o grandes, y combinan valores y comportamientos, es decir, datos junto con métodos que los manipulan.
Las estructuras y los registros, en cambio, comparan por valor. Si dos objetos tienen exactamente los mismos datos, para un struct o un record son el mismo objeto. Están pensados para piezas pequeñas con pocas propiedades, donde lo importante es el contenido y no la identidad.
¿Cuándo usar un record en C#? Úsalo cuando necesitas objetos inmutables que se comparan por valor, por ejemplo, mensajes entre microservicios o DTOs que viajan entre capas.
¿Por qué dos objetos iguales en una clase devuelven false?
Porque las clases comparan referencias, no contenido. Aunque tú veas los mismos valores en pantalla, internamente cada instancia vive en una posición de memoria distinta [02:54].
En el demo del proyecto se crean dos objetos Superman y Superman2 a partir de la clase Superhéroe, con exactamente los mismos datos. Al ejecutar:
csharp
Console.WriteLine(superman == superman2);
El resultado es false. Son dos instancias aisladas, con referencias independientes, así que C# las considera distintas aunque sus propiedades coincidan una a una.
Este comportamiento es útil cuando la identidad importa, por ejemplo cuando dos usuarios con el mismo nombre deben tratarse como entidades separadas. Pero se vuelve un problema cuando lo que te interesa es saber si dos paquetes de datos son equivalentes.
¿Cómo se declara y compara un record en C#?
Un record se declara casi igual que una clase, pero cambiando la palabra clave y aprovechando una sintaxis más compacta para sus propiedades [05:00].
La estructura mínima se ve así:
csharp
public record SuperheroeRecord(int Id, string Nombre, string IdentidadSecreta);
No necesitas escribir constructores ni propiedades una por una si no quieres añadir comportamiento. Para crear instancias tienes dos caminos:
- Usar la forma clásica con
new SuperheroeRecord(...) pasando los valores entre paréntesis.
- Omitir el nombre del tipo cuando ya está declarado y pasar directamente los valores en el
new.
Al repetir el ejercicio anterior con dos registros idénticos:
csharp
var reg1 = new SuperheroeRecord(1, "Superman", "Clark Kent");
var reg2 = new SuperheroeRecord(1, "Superman", "Clark Kent");
Console.WriteLine(reg1 == reg2);
El resultado es true. El record compara propiedad por propiedad de forma automática y confirma que los objetos son equivalentes.
¿Qué es un record en C# en una frase? Es un tipo que compara objetos por valor y se usa para datos inmutables, ideal para mensajería y DTOs.
¿Por qué los records son útiles en microservicios?
En arquitecturas de microservicios recibes múltiples mensajes de otros servicios y necesitas saber si dos payloads son equivalentes. Con una clase tendrías que revisar manualmente propiedad por propiedad. Con un record, C# hace esa comparación por ti gracias a su semántica por valor [08:25].
Esto reduce código repetitivo, evita errores al olvidar comparar algún campo y deja tu lógica de negocio más limpia.
¿Cuándo conviene usar struct, record o class?
La elección depende del tamaño del componente, la mutabilidad de los datos y la forma en que necesitas compararlos.
- Usa class cuando el componente tenga comportamiento, crezca en complejidad o necesites identidad por referencia.
- Usa struct para objetos pequeños enfocados en valores, sin lógica compleja.
- Usa record cuando los datos sean inmutables y la comparación por valor sea parte del flujo, como en mensajes o respuestas de API.
Como ejercicio, completa el record SuperheroeRecord con todas las propiedades que ya tiene la clase Superhéroe, ejecuta la comparación y verifica que sigue funcionando por valor. Después, crea un struct equivalente y compara los tres tipos en un mismo proyecto. ¿Qué diferencias notaste al ejecutar tu propio demo? Comparte tu experiencia en los comentarios.