Struct o Class en C#: el eterno debate de novatos y profesionales
\n\n¿Alguna vez te has preguntado por qué en C# existen dos formas muy similares de crear tu propio tipo de datos — class y struct? ¿Y por qué en Stack Overflow la pregunta «When should I use a struct rather than a class in C#?» acumula miles de visitas y cientos de respuestas? El caso es que detrás de la aparente simplicidad se esconde un matiz profundo que puede tanto acelerar tu programa como convertirlo en un semillero de errores.
En este artículo analizaremos en qué se diferencia struct de class, cuándo conviene usar struct y cuándo es mejor olvidarse de su existencia. Sin términos rebuscados, con ejemplos vivos y consejos prácticos. ¡Allá vamos!
\n\nLa diferencia principal: ¿pila o montón?
\n\nEl punto más importante que hay que entender son los tipos de valor (value types) y los tipos de referencia (reference types).
\n\n- \n
- Class — tipo de referencia. El objeto se almacena en el montón administrado (heap), y la variable solo contiene una referencia (dirección) a ese objeto. \n
- Struct — tipo de valor (value type). La variable almacena los datos directamente en la pila (stack) o dentro de otro objeto. \n
¿Suena abstracto? Pongamos un ejemplo. Imagina que los datos son un libro. Class es el título del libro y el número de estante donde está en la biblioteca. Struct es el libro mismo que llevas en el bolsillo. Cuando pasas un class a un método, pasas el número de estante. Cuando pasas un struct, entregas una copia del libro.
\n\nEjemplo de código: class vs struct
\n\npublic class PointClass\n{\n public int X { get; set; }\n public int Y { get; set; }\n\n public PointClass(int x, int y)\n {\n X = x;\n Y = y;\n }\n}\n\npublic struct PointStruct\n{\n public int X { get; set; }\n public int Y { get; set; }\n\n public PointStruct(int x, int y)\n {\n X = x;\n Y = y;\n }\n}\n\n// Uso\nvar pointClass = new PointClass(10, 20);\nvar pointStruct = new PointStruct(10, 20);\n\n// Paso a un método\nvoid ModifyPointClass(PointClass p) { p.X = 100; }\nvoid ModifyPointStruct(PointStruct p) { p.X = 100; }\n\nModifyPointClass(pointClass); // pointClass.X se vuelve 100\nModifyPointStruct(pointStruct); // pointStruct.X sigue siendo 10 — ¡copia!\n\n\n¿Ves? Struct se copia al pasarse. Esta es la diferencia clave que determina cuándo conviene usarla.
\n\nCuándo struct es tu amigo: 3 casos de hierro
\n\nMicrosoft recomienda usar struct si tu tipo de datos cumple TODAS las siguientes condiciones:
1. Datos pequeños y simples
\nStruct es ideal para conjuntos de datos pequeños (se recomienda no más de 16-24 bytes). Por ejemplo, un punto, un color, un vector, un número complejo, coordenadas.
\n\npublic struct RgbColor\n{\n public byte R { get; }\n public byte G { get; }\n public byte B { get; }\n\n public RgbColor(byte r, byte g, byte b)\n {\n R = r;\n G = g;\n B = b;\n }\n}\n\n\n¿Por qué? Porque los struct pequeños se copian rápido, y el almacenamiento en la pila reduce la carga del recolector de basura (GC).
\n\n2. Los objetos viven poco y no cambian
\nSi tus datos son valores inmutables (immutable), struct es una excelente opción. Por ejemplo, coordenadas en un mapa: no modificas un punto, creas uno nuevo.
\n\npublic struct GeoLocation\n{\n public double Latitude { get; }\n public double Longitude { get; }\n\n public GeoLocation(double lat, double lon)\n {\n Latitude = lat;\n Longitude = lon;\n }\n\n public GeoLocation MoveNorth(double meters)\n {\n // Devolvemos una nueva instancia, no modificamos la anterior\n return new GeoLocation(Latitude + meters / 111111.0, Longitude);\n }\n}\n\n\n