2011-01-31 7 views
28

Tenía la impresión de que en C#, los elementos struct se asignan en la pila y desaparecen cuando regresan de un método en el que se crearon. Pero, ¿qué sucede si coloco los valores de estructura en una lista y lo devuelvo? Los elementos sobreviven ¿Las instancias de la estructura a veces se asignan en el montón?¿Las estructuras siempre se asignan asignadas o, a veces, se asignan montones?

internal struct Stru 
{ 
    public int i; 
} 

internal class StruTry 
{ 
    public List<Stru> Get(int max) 
    { 
    var l = new List<Stru>(); 
    for (int i = 0; i < max; i++) 
     l.Add(new Stru {i=i}); 

    return l; 
    } 
} 

código de impresión 0, 1, 2

[Test] 
public void T() 
{ 
    var ll = new StruTry().Get(3); 
    foreach (var stru in ll) 
    Console.WriteLine("* "+ stru.i); 
} 

Respuesta

42

primer lugar, leer este post de Eric Lippert en The Stack is an Implementation Detail. Síguelo con The Truth about Value Types. En cuanto a su pregunta específica

¿A veces se asignan instancias de estructuras en el montón?

Sí, a veces se asignan en el montón. Hay muchos ejemplos de cuándo podrían asignarse en el montón. Si están encuadradas, o si son campos de una clase, o si son elementos de una matriz, o si son el valor de una variable del tipo de valor que se ha cerrado, etc.

Pero ¿Qué sucede si coloco los struct-values ​​en una lista y lo devuelvo? Los elementos sobreviven

Estás pensando en esto de la manera correcta, y este es uno de los puntos más importantes en donde se podría asignar un tipo de valor. Vea la segunda publicación a la que me referí en La verdad sobre los tipos de valores para más detalles. Pero simplemente mantenga The Stack es un detalle de implementación en mente. El punto clave es que realmente no necesita preocuparse por esto. Debería preocuparse por la diferencia semántica entre los tipos de valores y los tipos de referencia.

+3

Ese último punto acerca de solo preocuparse por "estoy pasando por valor o por referencia" y no "es mi objeto en la pila o en el montón" - es difícil para mí porque programo principalmente en C++. Creo que cualquier programador C/C++ piensa en términos de dónde vive un objeto. En C/C++, las estructuras (y las clases en C++) pueden vivir en cualquier lugar dependiendo de cómo se declaran. Parece que lo principal para cualquier programador de C/C++ para trabajar en C# es romper con este hábito y nunca pensar en dónde vive un objeto. –

+0

@jason ¿Qué hay de las estructuras genéricas como struct sockaddr, cómo se puede asignar la pila sin saber el tamaño correcto de la misma (ya que esta estructura genérica es por definición más pequeña que la estructura de IPv6 sockaddr_in6) – Bionix1441

+0

@jason ¿Qué significa esto "si son el valor de una variable del tipo de valor que se ha cerrado sobre "? – Pingpong

12

Las estructuras son como ints. Si tiene un int local, generalmente estará en la pila, si tiene una lista de entradas, se almacenan directamente en la matriz interna de la lista, que está en el montón. Las estructuras se comportan de la misma manera.

1

Todos los tipos pueden asignarse alguna vez en el montón. Además, heap/stack es un detalle de implementación del CLR y no de la especificación C#, por lo que nunca deberías confiar en tales cosas. Ver here para una buena publicación de blog sobre este tema.

1

Por lo que recuerdo ...

La ubicación de los tipos de valor depende del lugar donde se declaran. Las variables de método se asignan, se almacenan en la pila y se eliminan después de la ejecución del método en el marco de la pila. Los tipos de valor declarados como parte de un tipo de referencia se almacenan en el montón dentro de la estructura del tipo adjunto.

¡Avísame si me equivoco!

+2

Si por "variable de método" quiere decir variable local, su declaración no es completamente precisa. Por ejemplo, si la variable local se cierra en una expresión lambda, se izará para que sea miembro de la clase definida como compilada y se asignará en el montón al igual que otros campos de una clase. La clave es que dicha variable local podría vivir más tiempo que el método de definición y, por lo tanto, debe asignarse lejos de la pila. – jason

5

Pero, ¿qué ocurre si coloco los valores de estructura en una lista y los devuelvo? Los elementos sobreviven

Técnicamente, los valores agregados a 'Lista' no son los mismos valores, son copias basadas en valores. Si, por ejemplo, modificas el original, esos cambios no se llevarán a la copia de la lista. Además, 'Lista' devuelve una copia del valor en el índice indicado.Esto significa que si la estructura es mutable y usted modifica el valor devuelto desde la 'Lista', entonces el valor en el List<t> permanecerá sin cambios. Este no es el caso con las matrices, ya que el índice de la matriz proporciona acceso a la variable real.

1

Una ubicación de almacenamiento (variable, campo, parámetro, ranura de matriz, etc.) de tipo estructura mantiene los campos públicos y privados de la estructura dentro de ella. Si esa ubicación de almacenamiento está en la pila, los campos de la estructura estarán en la pila. Si está dentro de otra clase o estructura, los campos de la estructura se almacenarán como parte de esa otra clase o instancia de estructura.

Una ubicación de almacenamiento de tipo de clase contiene una referencia a un objeto de clase completa que siempre es o bien (1) almacenado en algún lugar completamente separado de la ubicación de almacenamiento que contiene una referencia, o (2) el objeto clase de la cual esa ubicación de almacenamiento es un campo.

Cuestiones relacionadas