2010-05-02 15 views
5

Como sabemos, en C# las estructuras se pasan por valor, no por referencia. Así que si tengo una estructura con los siguientes miembros de datos:C# struct con el objeto como miembro de datos

private struct MessageBox 
{ 
    // data members 
    private DateTime dm_DateTimeStamp; // a struct type 
    private TimeSpan dm_TimeSpanInterval; // also a struct 
    private ulong dm_MessageID; // System.Int64 type, struct 
    private String dm_strMessage; // an object (hence a reference is stored here) 
    // more methods, properties, etc ... 
} 

Así que cuando un cuadro de mensaje se pasa como un parámetro, se hace una copia en la pila, ¿verdad? ¿Qué significa eso en términos de cómo se copian los miembros de los datos? Los dos primeros son tipos de estructura, por lo que las copias deben hacerse de DateTime y TimeSpan. El tercer tipo es un primitivo, por lo que también se copia. Pero, ¿qué pasa con dm_strMessage, que es una referencia a un objeto? Cuando se copia, se crea otra referencia a la misma Cadena, ¿verdad? El objeto en sí reside en el montón, y NO se copia (solo hay una instancia del mismo en el montón). Ahora tenemos referencias al mismo objeto de tipo Cadena. Si se accede a las dos referencias desde diferentes hilos, es concebible que el objeto String podría corromperse al ser modificado desde dos direcciones diferentes simultáneamente. La documentación de MSDN dice que System.String es seguro para subprocesos. ¿Eso significa que la clase String tiene un mecanismo incorporado para evitar que un objeto se corrompa exactamente en el tipo de situación descrita aquí? Estoy tratando de averiguar si mi estructura de MessageBox tiene posibles fallas/trampas que son una estructura vs. una clase. Gracias por cualquier entrada.

Source.Energy.

+0

Aquí hay una pregunta similar con la respuesta de Jon Skeet al final http://bytes.com/topic/c-sharp/answers/553351-what-happens-reference-type-valuetype-struct –

Respuesta

4

Las cadenas no se pueden "dañar" mediante el acceso multiproceso porque son inmutables.

Sin embargo, debe evitar que las estructuras se puedan modificar. Lea this question y respuestas para obtener más información.

Estoy tratando de averiguar si mi estructura de MessageBox tiene posibles defectos/trampas que son una estructura vs. una clase.

Probablemente no debería ser una estructura. Consulte las directrices en MSDN para choosing between a class and a struct.

no definen una estructura a menos que el tipo tiene todas las siguientes características:

  • Es lógicamente representa un único valor, similar a los tipos primitivos (entero, doble, y así sucesivamente).
  • Tiene un tamaño de instancia inferior a 16 bytes.
  • Es inmutable.
  • No tendrá que estar en la caja con frecuencia.

Creo que su cuadro de mensaje rompe definitivamente la primera y segunda guías, y posiblemente también la tercera dependiendo de qué métodos están disponibles.

+0

Gracias por sus respuestas chicos. Sus respuestas me señalaron en la dirección correcta, y encontré * varias * publicaciones relacionadas con estructuras e inmutabilidad, por lo que ahora creo que entiendo mucho mejor los Conceptos. Hay otra pregunta de seguimiento que vale la pena abordar: si se crean estructuras en la pila (eso es correcto, ¿no?), Y administro una cola (es decir, System.Collection.Queue) de Structures, ¿eso significa que TODAS las estructuras en la cola se almacenan en la pila? Probablemente eso no es lo que quiero, ¿eh? Especialmente porque uno de los miembros de los datos es un String, que podría crecer mucho tiempo. –

+1

No es correcto que las estructuras siempre se creen en la pila. Y deberías tratar de no basar tu comprensión de las clases y las estructuras en si están almacenadas en la pila o en el montón. Este es un detalle de implementación y podría cambiar en el futuro (pero probablemente no lo hará). Pero para responder a su pregunta, la * referencia * a una cadena se puede almacenar en la pila o en el montón, pero los * datos de carácter * en una cadena estarán en el montón incluso para cadenas en estructuras. –

0

Desde la perspectiva de GC, pasar una única estructura no es muy diferente de pasar los campos como parámetros individuales. Ciertamente, no hay nada de qué preocuparse cuando pasa una cuerda en una estructura, frente a pasar una cuerda como un parámetro simple.

Las cadenas son inmutables, por lo que son imposibles de corromper, sin importar cuántos hilos las compartan.

2

En primer lugar, su primera oración implica que usted piensa que las clases se pasan por referencia. Este no es el caso: la referencia se pasa por valor (de forma predeterminada).Ver my article on parameter passing para más detalles. Cuando comprenda esto, puede aclarar otros aspectos.

Su pregunta es realmente de dos cosas diferentes:

  • cómo los valores struct son copiados
  • ¿Qué tan seguro es compartir cadenas entre hilos

creo que va a ayudar si separa los dos.

Al copiar el valor de una estructura, los miembros se tratan de la misma manera, ya sean tipos de valores o tipos de referencia. El valor simplemente se copia, bit a bit. Lo importante de entender es que el valor de dm_strMessage es una referencia, no un objeto de cadena. Esa referencia es copiada.

Esto no es más perjudicial que este código:

string message = GetMessageFromSomewhere(); 
string otherMessage = message; 

Exactamente lo mismo sucede: el valor de message se copia en otherMessage: las dos variables tienen el mismo valor, que es una referencia a un único objeto de cuerda

Hasta ahora, esto no tiene nada que ver con el enhebrado. Ahora bien, si comparte una referencia de cadena entre varios hilos, eso es seguro, porque las cadenas son inmutables. No puede cambiar el contenido de un objeto de cadena, por lo tanto, dos cadenas pueden leer datos del mismo objeto sin riesgos de corrupción. Lo mismo es no verdadero de muchos otros tipos en .NET. Por ejemplo, no es seguro compartir un List<T> entre varios hilos que potencialmente van a modificar la lista.

+0

Justo, Jon, gracias. Para aclarar: en su ejemplo, el mensaje variable (de tipo String) es una referencia a un objeto String, de modo que cuando el mensaje se pasa como un parámetro, la referencia misma se copia, lo que significa que se transfiere por valor, como dijo. Los datos que representan el objeto String residen en el montón, y definitivamente NO se copian. Entonces, después de que se pasa el mensaje, y asumiendo que no sale del alcance, terminamos con dos referencias al mismo objeto String. ¿Todo lo anterior es preciso y correcto? Y sí, ahora veo que mi pregunta original no tiene que ver demasiado con la seguridad de subprocesos/subprocesos. –

+0

Sí, eso es todo correcto –

Cuestiones relacionadas