una propiedades propiedad programacion metodos estructuras estructura ejemplos datos clases clase autoimplementadas c# class struct value-type reference-type

c# - propiedades - propiedad en una clase



¿Puedes tener una clase en una estructura? (4)

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


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.



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 la 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 compila y ejecuta para mostrar 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; } } } }


Si uno de los campos de una estructura es un tipo de clase, ese campo mantendrá la identidad de un objeto de clase o bien una referencia nula. Si el objeto de clase en cuestión es inmutable (por ejemplo, string ), el almacenamiento de su identidad también almacenará efectivamente su contenido. Sin embargo, si el objeto de clase en cuestión es mutable, el almacenamiento de la identidad será un medio eficaz de almacenar el contenido si y solo si la referencia nunca caerá en manos de ningún código que pueda mutar una vez que se almacena en el campo .

Generalmente, uno 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 en lugar de su contenido. Por ejemplo, uno podría definir una estructura `FormerControlBounds` que contiene campos de tipo` Control` y `Rectangle`, y representa los` Bounds` que el control tenía en algún momento en el tiempo, con el propósito de poder restaurar el control más tarde a su posición anterior. El objetivo del campo `Control` no sería contener una copia del estado del control, sino identificar el control cuya posición debe restaurarse. En general, la estructura debe evitar el acceso a cualquier miembro mutable del objeto al que mantiene una referencia, excepto en los casos en que está claro que dicho acceso se refiere al estado actual mutable del objeto en cuestión (por ejemplo, en un `CaptureControlPosition` o` Método RestoreControlToCapturedPosition`, o una propiedad `ControlHasMoved`).
  2. El campo es `privado`, los únicos métodos que lo leen lo hacen con el propósito de examinar sus propiedades sin exponer el objeto mismo a código externo, y los únicos métodos que lo escriben crearán un nuevo objeto, realizarán todas las mutaciones que alguna vez le sucederán, y luego almacenar una referencia a ese objeto. Uno podría, por ejemplo, diseñar una `struct` que se comportara como una matriz, pero con semántica de valores, haciendo que la estructura mantenga una matriz en un campo privado, y al tener 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 por ningún código que pudiera mutarla.

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

El escenario # 2 es menos común. Por desgracia, no hay forma de decirle al compilador que los métodos de estructura distintos de los modificadores de propiedad modificarán una estructura y que su uso debería estar prohibido en contextos de solo lectura; uno podría tener una estructura que se comportara como List<T> , pero con semántica de valores e incluyera un método Add , pero un intento de invocar Add en una instancia struct de solo lectura generaría un código falso en lugar de un error de compilación. Además, los métodos de mutación y los establecedores de propiedades en tales estructuras generalmente se comportarán bastante mal. Dichas estructuras pueden ser útiles cuando existen como un envoltorio inmutable en una clase que de otro modo sería mutable; si tal estructura nunca se incluye, el rendimiento a menudo será mejor que una clase. Si se encasilla exactamente una vez (por ejemplo, al usar un tipo de interfaz), el rendimiento generalmente será comparable a una clase. Si se encasilla repetidamente, el rendimiento puede ser mucho peor que una clase.