Si una entidad va a ser inmutable, la cuestión de si usar una estructura o una clase generalmente será de rendimiento en lugar de semántica. En un sistema de 32/64 bits, las referencias de clase requieren 4/8 bytes para almacenar, independientemente de la cantidad de información en la clase; copiar una referencia de clase requerirá copiar 4/8 bytes. Por otro lado, cada instancia de clase distinta de tendrá 8/16 bytes de sobrecarga además de la información que contiene y el costo de memoria de las referencias a ella.Supongamos que uno quiere una matriz de 500 entidades, cada una con cuatro enteros de 32 bits. Si la entidad es un tipo de estructura, la matriz requerirá 8,000 bytes independientemente de si las 500 entidades son todas idénticas, todas diferentes o en algún punto intermedio. Si la entidad es un tipo de clase, la matriz de 500 referencias tomará 4.000 bytes. Si todas esas referencias apuntan a objetos diferentes, los objetos requerirían 24 bytes adicionales cada uno (12,000 bytes para los 500), un total de 16,000 bytes, el doble del costo de almacenamiento de un tipo de estructura. Por otro lado, si el código creó una instancia de objeto y luego copió una referencia a las 500 ranuras de la matriz, el costo total sería de 24 bytes para esa instancia y de 4.000 para la matriz, un total de 4.024 bytes. Un gran ahorro. Pocas situaciones funcionarían tan bien como la última, pero en algunos casos podría ser posible copiar algunas referencias a suficientes ranuras de arreglos para que valga la pena compartirlas.
Si se supone que la entidad es mutable, la cuestión de si usar una clase o estructura es de alguna manera más fácil. Asumir "cosa" es o bien una estructura o clase que tiene un campo entero llamado x, y uno hace lo siguiente código:
Thing t1,t2;
...
t2 = t1;
t2.x = 5;
¿Se quiere la última afirmación de afectar t1.x?
Si Thing es un tipo de clase, t1 y t2 serán equivalentes, lo que significa que t1.x y t2.x también serán equivalentes. Por lo tanto, la segunda declaración afectará a t1.x. Si Thing es un tipo de estructura, t1 y t2 serán instancias diferentes, lo que significa que t1.x y t2.x se referirán a diferentes enteros. Por lo tanto, la segunda declaración no afectará a t1.x.
Las estructuras mutables y las clases mutables tienen comportamientos fundamentalmente diferentes, aunque .net tiene algunas peculiaridades en el manejo de las mutaciones estructurales. Si uno quiere un comportamiento de tipo valor (lo que significa que "t2 = t1" copiará los datos de t1 a t2 dejando t1 y t2 como instancias distintas), y si uno puede vivir con las peculiaridades en el manejo de tipos de valores de .net, use una estructura. Si uno quiere semántica de tipo de valor pero los caprichos de .net causarían una semántica de tipo de valor roto en la aplicación, utilice una clase y murmure.
Solo un recordatorio: lo que la mayoría de la gente tiende a olvidar en este contexto es que en C# las estructuras también pueden tener métodos. –