una estructura en C# es en su corazón ni más ni menos que un montón de variables pegados con cinta adhesiva. Si uno quiere que cada variable de un tipo en particular represente un grupo de variables independientes pero relacionadas (como las coordenadas de un punto) pegadas con cinta adhesiva, a menudo es mejor usar una estructura de campo expuesto que una clase, independientemente de si "montón" significa dos o veinte. Tenga en cuenta que aunque el consejo de struct-versus-class de Microsoft es bueno para los tipos de datos que encapsulan un único valor, se debe considerar inaplicable para los tipos cuyo objetivo es encapsular valores independientes pero relacionados. Cuanto mayor sea el grado en que las variables son independientes, mayores serán las ventajas de usar una estructura de campo expuesto.
Si se desea utilizar una clase para encapsular un grupo de variables independientes, hay dos maneras en que puede hacerlo, ninguna de las cuales es terriblemente conveniente. Se puede usar una clase inmutable, en cuyo caso cualquier ubicación de almacenamiento no nulo de ese tipo de clase encapsulará los valores mantenidos por la instancia identificada de ese modo, y una ubicación de almacenamiento se puede copiar a otra para hacer que la nueva encapsule esos mismos valores. Desafortunadamente, cambiar uno de los valores encapsulados por una ubicación de almacenamiento generalmente requerirá construir una nueva instancia que sea exactamente igual a la antigua excepto que se modifique ese valor. Por ejemplo, si uno tiene una variable pt
del tipo Immutable3dPoint
y una desea aumentar pt.X
en uno, uno tendría que hacer algo como: pt = new Immutable3dPoint(pt.X+1, pt.Y, pt.Z);
Quizás tolerable si el tipo solo encapsula tres valores, pero bastante molesto si hay muchos.
El otro enfoque basado en clases es usar una clase mutable; esto generalmente requiere que uno se asegure de que cada ubicación de almacenamiento del tipo de clase contenga la única referencia en cualquier parte del universo a una instancia de esa clase. Cuando se crea una ubicación de almacenamiento, se debe construir una nueva instancia y almacenar allí una referencia. Si desea copiar los valores de la ubicación de almacenamiento P
a la ubicación de almacenamiento Q
, a otro, debe copiar todos los campos o propiedades de una instancia a la otra (quizás haciendo que el tipo implemente un método CopyFrom
y diciendo Q.CopyFrom(P);
. si en cambio dice Q=P;
que pueden parecer a trabajar, pero los futuros intentos de modificar P
también modificarán Q
y viceversa. clases mutables pueden trabajar, y que a veces puede ser eficaz, pero es muy fácil de estropear las cosas.
Las estructuras de campo expuesto combinan la conveniente semántica de copia de valores de las clases inmutables con las convenientes modificaciones por partes permitidas por las clases mutables. Las estructuras grandes son más lentas de copiar que las referencias a obj inmutables. Sin embargo, el costo de modificar parte de una estructura de campo expuesto depende únicamente del alcance de la modificación, más que del tamaño total de la estructura. Por el contrario, el costo de cambiar una pieza de datos encapsulada en un tipo de clase inmutable será proporcional al tamaño total de la clase.
Cambiaría tu respuesta de una frase para "solo usar clases a menos que realmente sepas lo que estás haciendo" –
@Joel - ¡Esa es una regla con la que puedo vivir! –
@Joel: el único problema con esa idea es que la mayoría de las personas solo piensan que saben lo que hacen. – chsh