Pregunta

¿Es posible en C# tener una Estructura con una variable miembro que sea de tipo Clase?Si es así, ¿dónde se almacena la información, en la pila, en el montón o en ambos?

¿Fue útil?

Solución

Sí tu puedes.El puntero a la variable miembro de la clase se almacena. en la pila con el resto de los valores de la estructura, y los datos de la instancia de clase se almacenan en el montón.

Las estructuras también pueden contener definiciones de clases como miembros (clases internas).

Aquí hay un código realmente inútil que al menos se compila y ejecuta para demostrar que es posible:

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyStr m = new MyStr();
            m.Foo();

            MyStr.MyStrInner mi = new MyStr.MyStrInner();
            mi.Bar();

            Console.ReadLine();
        }
    }

    public class Myclass
    {
        public int a;
    }

    struct MyStr
    {
        Myclass mc;

        public void Foo()
        {
            mc = new Myclass();
            mc.a = 1;
        }

        public class MyStrInner
        {
            string x = "abc";

            public string Bar()
            {
                return x;
            }
        }
    }
}

Otros consejos

El contenido de la clase se almacena en el montón.

Una referencia a la clase (que es casi lo mismo que un puntero) se almacena con el contenido de la estructura.El lugar donde se almacena el contenido de la estructura depende de si es una variable local, un parámetro de método o un miembro de una clase, y si ha sido encuadrado o capturado por un cierre.

Si uno de los campos de una estructura es un tipo de clase, ese campo contendrá el identidad de un objeto de clase o bien una referencia nula.Si el objeto de clase en cuestión es inmutable (p. ej. string), almacenar su identidad efectivamente también almacenará su contenido.Sin embargo, si el objeto de clase en cuestión es mutable, almacenar la identidad será un medio eficaz para almacenar el contenido. si y sólo si la referencia nunca caerá en manos de ningún código que pueda mutarla una vez almacenada en el campo.

Generalmente, se debe evitar almacenar tipos de clases mutables dentro de una estructura a menos que se aplique una de dos situaciones:

  1. Lo que a uno le interesa es, de hecho, la identidad del objeto de clase más que su contenido.Por ejemplo, se podría definir una estructura `FormerControlBounds` que contenga campos de tipo `Control` y `Rectangle`, y represente los `Bounds` que ese control tuvo en algún momento, con el fin de poder restaurarlo posteriormente. a su posición anterior.El propósito del campo "Control" no sería contener una copia del estado del control, sino más bien identificar el control cuya posición debe restaurarse.Generalmente, la estructura debe evitar el acceso a cualquier miembro mutable del objeto al que tiene una referencia, excepto en los casos en los que esté claro que dicho acceso se refiere al estado mutable actual del objeto en cuestión (por ejemplo,en un método `CaptureControlPosition` o `RestoreControlToCapturedPosition`, o una propiedad `ControlHasMoved`).
  2. El campo es "privado", los únicos métodos que lo leen lo hacen con el fin de examinar sus propiedades sin exponer el objeto en sí a código externo, y los únicos métodos que lo escriben crearán un nuevo objeto y realizarán todas las mutaciones. que alguna vez le sucederán y luego almacenar una referencia a ese objeto.Se podría, por ejemplo, diseñar una "estructura" que se comportara de manera muy similar a una matriz, pero con semántica de valores, haciendo que la estructura contenga una matriz en un campo privado y haciendo que cada intento de escribir la matriz cree una nueva matriz con datos. desde el anterior, modifique la nueva matriz y almacene la matriz modificada en ese campo.Tenga en cuenta que, aunque la matriz en sí sería un tipo mutable, cada instancia de matriz que alguna vez se almacenaría en el campo sería efectivamente inmutable, ya que nunca sería accesible mediante ningún código que pudiera mutarla.

Tenga en cuenta que el escenario n.° 1 es bastante común con tipos genéricos;por ejemplo, es muy común tener un diccionario cuyos "valores" sean las identidades de objetos mutables;enumerar ese diccionario devolverá instancias de KeyValuePair cuyo Value El campo contiene ese tipo mutable.

El escenario número 2 es menos común.Lamentablemente, no hay forma de decirle al compilador que los métodos de estructura distintos de los que establecen propiedades modificarán una estructura y, por lo tanto, su uso debería estar prohibido en contextos de solo lectura;uno podría tener una estructura que se comportara como un List<T>, pero con semántica de valor, e incluyó un Add método, pero un intento de llamar Add en una instancia de estructura de solo lectura generaría código falso en lugar de un error del compilador.Además, los métodos mutantes y los establecedores de propiedades en dichas estructuras generalmente funcionarán bastante mal.Estas estructuras pueden resultar útiles cuando existen como un contenedor inmutable en una clase que de otro modo sería mutable;Si dicha estructura nunca está encajonada, el rendimiento suele ser mejor que el de una clase.Si se encajona exactamente una vez (p. ej.al convertirlo en un tipo de interfaz), el rendimiento generalmente será comparable al de una clase.Si se encajona repetidamente, el rendimiento puede ser mucho peor que el de una clase.

Probablemente no sea una práctica recomendada hacerlo:ver http://msdn.microsoft.com/en-us/library/ms229017(VS.85).aspx

Los tipos de referencia se asignan en el montón, y el recolector de basura maneja la gestión de la memoria.

Los tipos de valor se asignan en la pila o en línea y se desaniman cuando salen del alcance.

En general, los tipos de valor son más baratos de asignar y desasignar.Sin embargo, si se usan en escenarios que requieren una cantidad significativa de boxeo y unboxing, funcionan mal en comparación con los tipos de referencia.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top