La diferencia más importante entre ay classa structes lo que sucede en la siguiente situación:
Cosa thing1 = nueva Cosa ();
thing1.somePropertyOrField = 5;
Cosa thing2 = thing1;
thing2.somePropertyOrField = 9;
¿Cuál debería ser el efecto de la última declaración thing1.somePropertyOrField? Si Thinguna estructura, y somePropertyOrFieldes un campo público expuesto, los objetos thing1y thing2serán "separados" entre sí, por lo que la última declaración no afectará thing1. Si Thinges una clase, entonces thing1y se thing2unirán entre sí, por lo que se escribirá la última declaración thing1.somePropertyOrField. Uno debería usar una estructura en los casos en que la semántica anterior tendría más sentido, y debería usar una clase en los casos en que la última semántica tuviera más sentido.
Tenga en cuenta que si bien algunas personas aconsejan que el deseo de hacer algo mutable es un argumento a favor de que sea la clase, sugeriría lo contrario: si algo que existe con el propósito de mantener algunos datos va a ser mutable, y Si no será obvio si las instancias están unidas a algo, la cosa debería ser una estructura (probablemente con campos expuestos) para dejar en claro que las instancias no están unidas a nada más.
Por ejemplo, considere las declaraciones:
Persona somePerson = myPeople.GetPerson ("123-45-6789");
somePerson.Name = "Mary Johnson"; // Había sido "Mary Smith"
¿La segunda declaración alterará la información almacenada myPeople? Si Persones una estructura de campo expuesto, no lo será, y el hecho de que no lo sea será una consecuencia obvia de ser una estructura de campo expuesto ; si Persones una estructura y uno desea actualizar myPeople, claramente tendría que hacer algo como eso myPeople.UpdatePerson("123-45-6789", somePerson). PersonSin embargo, si es una clase, puede ser mucho más difícil determinar si el código anterior nunca actualizará el contenido MyPeople, siempre lo actualizará o, a veces, lo actualizará.
Con respecto a la noción de que las estructuras deben ser "inmutables", no estoy de acuerdo en general. Hay casos de uso válidos para estructuras "inmutables" (donde los invariantes se imponen en un constructor) pero requieren que una estructura completa se reescriba cada vez que cualquier parte de ella cambie es incómoda, derrochadora y más propensa a causar errores de lo que simplemente expondría campos directamente. Por ejemplo, considere una PhoneNumberestructura cuyos campos, incluir entre otros, AreaCodey Exchange, y suponga que uno tiene un List<PhoneNumber>. El efecto de lo siguiente debería ser bastante claro:
para (int i = 0; i <myList.Count; i ++)
{
PhoneNumber theNumber = myList [i];
if (theNumber.AreaCode == "312")
{
cadena newExchange = "";
if (new312to708Exchanges. TryGetValue (theNumber.Exchange), out newExchange)
{
theNumber.AreaCode = "708";
theNumber.Exchange = newExchange;
myList [i] = theNumber;
}
}
}
Tenga en cuenta que nada en el código anterior sabe o no le importa ningún campo que PhoneNumberno sea AreaCodey Exchange. Si PhoneNumberfuera una estructura llamada "inmutable", sería necesario que proporcionara un withXXmétodo para cada campo, que devolvería una nueva instancia de estructura que contenía el valor pasado en el campo indicado, o de lo contrario sería necesario para código como el anterior para saber acerca de cada campo en la estructura. No exactamente atractivo.
Por cierto, hay al menos dos casos en los que las estructuras pueden contener referencias a tipos mutables.
- La semántica de la estructura indica que está almacenando la identidad del objeto en cuestión, en lugar de como un atajo para mantener las propiedades del objeto. Por ejemplo, un `KeyValuePair` mantendría las identidades de ciertos botones, pero no se esperaría que contuviera una información persistente sobre las posiciones de esos botones, los estados resaltados, etc.
- La estructura sabe que tiene la única referencia a ese objeto, nadie más obtendrá una referencia, y cualquier mutación que alguna vez se realice a ese objeto se habrá realizado antes de que se almacene una referencia a él en cualquier lugar.
En el primer escenario, la IDENTIDAD del objeto será inmutable; en el segundo, la clase del objeto anidado puede no imponer la inmutabilidad, pero la estructura que contiene la referencia sí lo hará.