2010-01-04 21 views
9

Me estoy confundiendo con lo que sucede en la pila y el montón con respecto a las propiedades del tipo de valor en las clases.Devolviendo un tipo de valor de una propiedad

Mi entendimiento hasta el momento:

Al crear una clase con una estructura (tipo de valor) de esta manera:

class Foo 
{ 
    private Bar _BarStruct; 
    public Bar BarStruct 
    { 
    get {return _BarStruct; } 
    set {_BarStruct = value; } 
    } 
} 

private struct Bar 
{ 
    public int Number; 
    Bar() 
    { 
    Number = 1; 
    } 
    Bar(int i) 
    { 
    Number = i; 
    } 
} 

Si crea una instancia de clase de este modo:

Foo fooObj = new Foo(); 

La pila y el montón se verán así:

https://i962.photobucket.com/albums/ae105/acardy/stackheap-1.jpg(https://i962.photobucket.com/albums/ae105/acardy/stackheap-1.jpg)

... donde la estructura de barras está incrustada en la clase Foo en el montón. Esto tiene sentido para mí, pero empiezo a perderlo cuando consideramos modificar el número entero en la clase BarStruct, dentro del objeto Foo. Por ejemplo:

Foo fooObj = new Foo(); 
fooObj.BarStruct.Number = 1; 

Según entiendo, esto debería ser devolviendo una copia del BarStruct vivir en la pila, lo que significa que cualquier cambio de un miembro de BarStruct no se llevarían a través del objeto, por lo que la última línea de arriba da un error.

¿Es así de derecho?

Si es así, mi pregunta es, ¿cómo es que una misión como esta:

fooObj.BarStruct = new Bar(2); 

... es válida y cambia el valor de área? Sin duda, esto solo está cambiando el valor en la pila? Además, (poco a poco) me resulta tan confuso que puedes usar lo nuevo en un tipo de valor. Para mí, lo nuevo es para asignar en el montón (según C++) y no se siente natural hacer esto para los elementos de la pila.

Así que para repetir la pregunta, ¿estoy en lo cierto al asumir que sucede cuando se llama a una propiedad que contiene una estructura y por qué puede asignar una nueva estructura a una copia y aún así cambia la referencia en el ¿montón?

Realmente espero que todo esto tenga sentido.

¡Grita si necesitas una aclaración!

Ta,

Andy.

+0

@Andy, +1 bonita pregunta. Apuesto a que si le preguntas a 10 programadores experimentados de C#, menos de la mitad sabría exactamente qué está pasando aquí. Las estructuras son complicadas porque parecen clases pero tienen diferencias importantes. – Ash

Respuesta

10

En cuanto a esta asignación:

fooObj.BarStruct = new Bar(2); 

La asignación no está cambiando el valor en la pila - que está llamando a la setter para la propiedad.

En otras palabras, mientras que su primera asignación es equivalente a:

fooObj.get_BarStruct().Number = 1; // Bad 

el segundo es equivalente a:

fooObj.set_BarStruct(new Bar(2)); 

ayuda eso?

Tenga en cuenta que la asignación problemática se convierte en un problema sin importancia si usted hace que su tipo de valor sea inmutable para empezar, lo que ayuda en general, de hecho. Los tipos de valores mutables son una idea realmente mala en C#; puedes entrar en un sinfín de problemas con ellos.

En términos de sus expectativas de "nuevo" - trate de no pensar en C++, básicamente. C# no es C++, y varias cosas (destructores, genéricos, comportamiento durante la construcción) te confundirán si tratas de escribir C++ efectivamente en C#. Una instrucción "nueva" crea una nueva instancia de un tipo, ya sea un tipo de valor o un tipo de referencia.

+0

En realidad, eso ayuda mucho, realmente debería haberlo pensado un poco más lógicamente, ¡pero espero que también pueda ayudar a otros! :) ¡Muchas gracias! – Andy

+0

Jon, me acaban de atrapar con esto usando System.Drawing.Rectangle y System.Drawing.Point cuando traté de envolverlos en propiedades. Microsoft realmente debería haber hecho estas estructuras inmutables. – Ash

+0

@Ash: estoy de acuerdo. Las estructuras mutables pueden ser útiles en un conjunto * muy * restringido de circunstancias, pero casi siempre son más peligrosas que beneficiosas. –

Cuestiones relacionadas