Si s1
y s2
son estructuras de tipo Foo
, con campos f1
, f2
y f3,
de tipos t1
, t2
y t3
, la La declaración s1 = s2
es semánticamente equivalente a
s1.f1 = s2.f1;
s1.f2 = s2.f2;
s1.f3 = s2.f3;
salvo que uno no debe asumir el orden de las operaciones de asignación (o incluso el orden relativo de lecturas y escrituras; el código generado podría, por ejemplo, leer los tres campos en registros, y luego escribir los tres campos). Todos los campos se copiarán, independientemente de si son públicos o privados, mutables o los llamados inmutables. No se llamará a los getters o setters de propiedades; ni la estructura de origen ni la de destino recibirán ninguna notificación de que los campos de las estructuras se están duplicando o sobrescribiendo.
Una declaración this = new Foo(whatever);
es en C# (*) equivalente a
Foo temp;
call Foo's constructor (out temp, whatever);
this.f1 = temp.f1;
this.f2 = temp.f2;
this.f3 = temp.f3;
(*) semántica Struct constructor en VB.net son diferentes
Como se indicó anteriormente, las asignaciones de campo se realizan independientemente de si los campos son públicos o privados, y sin importar si son supuestamente inmutables.
Una de las razones creo (en contra de la opinión de otras personas) que estructuras a menudo se debe exponer a campos variables es que sintaxis como:
// Assume myKVP is a field of type KeyValuePair<Wizzle, int>
rr = new KeyValuePair<myKVP.Key, myKVP.Value+1>;
hace que parezca como si myKVP
se referirá a una instancia diferente después la asignación de lo que tenía antes, cuando lo que está sucediendo realmente es:
// Assumes backing fields are named _Key and _Value
// Note that C# won't allow one to write private fields directly, but the
// act of copying one struct instance to another copies all the fields,
// public and private, from the source instance to the destination.
KeyValuePair<Wizzle, int> temp;
temp._Key = myKVP.Key; // Constructor has access to backing fields
temp._Value = myKVP.Value+1;
myKVP._Key = temp._Key; // Struct assignment copies all fields, public and private
myKVP.Value = temp.Value;
En otras palabras, la declaración no hace myKVP
informe a una instancia diferente; en su lugar, crea una nueva instancia, muta la instancia anterior al sobrescribir sus campos con los de la instancia nueva y luego descarta la nueva instancia. Si algún código estaba evaluando myKVP.ToString()
mientras se llevaba a cabo la asignación anterior, la mutación afectaría a la instancia de myMVP
que se estaba imprimiendo.
Las estructuras pueden tener una semántica útil, pero las llamadas estructuras "inmutables" no lo son. Las estructuras no triviales (aquellas para las que es posible crear un valor diferente del predeterminado) son mutables si y solo si se mantienen en las ubicaciones de almacenamiento mutable , independientemente de cualquier semántica impuesta por el tipo. Estructuras mutantes, es decir, estructuras que modifican this
en cualquier método, excepto en constructores y establecedores de propiedades, pueden tener algunos comportamientos inesperados porque los compiladores no pueden prohibir la invocación de otros métodos que mutarán this
en las instancias de estructura inmutables. La exposición pública de los campos estructurales, sin embargo, no representa ningún peligro. Dado que todos los campos de una instancia mutable de una estructura no trivial son inherentemente modificables, independientemente de los intentos que la estructura pueda hacer para permitir la mutación, y todos los campos de una instancia inmutable de una estructura son inmutables incluso si están expuestos, una estructura que se esfuerza por hacer que sus campos sean "inmutables" realmente está mintiendo. Una mentira que a veces puede ser útil (por ejemplo, si se supone que los contenidos del campo obedecen a ciertas invariantes) pero que no se debe contar sin una causa real.
A menos que esté loco, eso es un error. – ChaosPandion
@ ChaosPandion: O los dos estamos locos o estoy de acuerdo. Tal vez reflector idiota? –
@ ChaosPandion esto es completamente legal para 'struct' en C# – JaredPar