Pregunta

  

Hay casos en que una instancia de un   el tipo de valor debe tratarse como un   instancia de un tipo de referencia. Para   situaciones como esta, un tipo de valor   instancia puede convertirse en un   instancia de tipo de referencia a través de un   proceso llamado boxeo. Cuando un valor   tipo instancia está en caja, el almacenamiento es   asignado en el montón y el   el valor de la instancia se copia en ese   espacio. Una referencia a este almacenamiento es   colocado en la pila. El valor en caja   es un objeto, un tipo de referencia que   contiene el contenido del valor   escriba instancia.

     

Comprensión del sistema de tipos comunes de .NET

En Wikipedia hay un ejemplo para Java. Pero en C #, ¿cuáles son algunos casos en los que uno tendría que boxear un tipo de valor? O sería una pregunta mejor / similar, ¿por qué querría almacenar un tipo de valor en el montón (en caja) en lugar de en la pila?

¿Fue útil?

Solución

En general, generalmente querrá evitar el encajonamiento de sus tipos de valor.

Sin embargo, hay casos raros en los que esto es útil. Si necesita apuntar al marco 1.1, por ejemplo, no tendrá acceso a las colecciones genéricas. Cualquier uso de las colecciones en .NET 1.1 requeriría tratar su tipo de valor como un System.Object, lo que causa el boxing / unboxing.

Todavía hay casos para que esto sea útil en .NET 2.0+. Cada vez que desee aprovechar el hecho de que todos los tipos, incluidos los tipos de valor, pueden tratarse como un objeto directamente, es posible que necesite usar boxing / unboxing. Esto puede ser útil a veces, ya que le permite guardar cualquier tipo en una colección (mediante el uso de objetos en lugar de T en una colección genérica), pero en general, es mejor evitar esto, ya que está perdiendo la seguridad de los tipos. Sin embargo, el único caso en el que el boxeo ocurre con frecuencia es cuando usa Reflection: muchas de las llamadas en reflexión requerirán boxing / unboxing cuando trabaje con tipos de valor, ya que el tipo no se conoce de antemano.

Otros consejos

Casi nunca hay una buena razón para encuadrar deliberadamente un tipo de valor. Casi siempre, la razón para encuadrar un tipo de valor es almacenarlo en alguna colección que no tenga en cuenta el tipo. El antiguo ArrayList , por ejemplo, es una colección de objetos, que son tipos de referencia. La única forma de recopilar, por ejemplo, enteros, es encuadrarlos como objetos y pasarlos a ArrayList.

Hoy en día, tenemos colecciones genéricas, por lo que este es un problema menor.

El boxeo generalmente ocurre automáticamente en .NET cuando tienen que hacerlo; a menudo cuando pasa un tipo de valor a algo que espera un tipo de referencia. Un ejemplo común es string.Format (). Cuando pasa tipos de valores primitivos a este método, se encuadran como parte de la llamada. Entonces:

int x = 10;
string s = string.Format( "The value of x is {0}", x ); // x is boxed here

Esto ilustra un escenario simple donde un tipo de valor (x) se encuadra automáticamente para pasar a un método que espera un objeto. En general, desea evitar los tipos de valores de boxeo cuando sea posible ... pero en algunos casos es muy útil.

De manera interesante, cuando usas genéricos en .NET, los tipos de valor no se encuadran cuando se usan como parámetros o miembros del tipo. Lo que hace que los genéricos sean más eficientes que el código C # anterior (como ArrayList) que trata todo como {objeto} para ser independiente del tipo. Esto agrega una razón más para usar colecciones genéricas, como List<T> o Dictionary<T,K> sobre ArrayList o Hashtable.

Te recomendaría 2 buenos artículos de Eric Lippert

http : //blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx

http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two.aspx

Aquí está la cita con la que estaría 100% de acuerdo

  

Uso de la pila para locales de valor   tipo es solo una optimización que el   CLR realiza en su nombre.   La característica relevante de los tipos de valor es   que tienen la semántica de ser   copiado por valor, no que a veces   su desasignación puede ser optimizada por   el tiempo de ejecución.

En el 99% de los desarrolladores de aplicaciones no debería importarles por qué los tipos de Valor están en la pila y no en el montón y qué ganancia de rendimiento podríamos tener aquí. Juts tiene en mente reglas muy simples:

  1. Evite el boxeo / unboxing cuando no necesario, usar colecciones de genéricos. La mayoría de los problemas no ocurren cuando define tus propios tipos, pero cuando usar los tipos existentes de manera inadecuada (definido por Microsoft o su colegas)
  2. Haz tus tipos de valor sencillo. Si necesitas tener una estructura con 10-20 campos, supongo que Mejor crear una clase. Imagina, todos esos campos se copiarán cada vez cuando ocasionalmente lo pasas funcionar por valor ...
  3. No creo que sea muy útil tener tipos de valor con tipo de referencia campos adentro. Me gusta struct con Cadena y campos de objeto.
  4. Defina qué tipo necesita según funcionalidad requerida, no en donde Debe ser almacenado. Las estructuras tienen funcionalidad limitada en comparación con clases, entonces si struct no puede proporcionar la funcionalidad requerida, como constructor predeterminado, definir clase.
  5. Si algo puede realizar alguna acciones con los datos de otros tipos, generalmente se define como un clase. Para operaciones de estructuras con se deben definir diferentes tipos solo si puedes emitir un tipo a otro. Digamos que puedes agregar int a doble porque puedes enviar int a doble.
  6. Si algo no tiene estado, es una clase.
  7. Cuando dudes, usa tipos de referencia. :-)

Cualquier regla permite exclusiones en casos especiales, pero no intente optimizar en exceso.

p.s. Conocí a algunos desarrolladores de ASP.NET con 2-3 años de experiencia que no conocen la diferencia entre stack y heap. :-( No contrataría a esa persona si soy entrevistador, pero no porque el boxeo / unboxing podría ser un cuello de botella en cualquiera de los sitios ASP.NET que he visto.

Creo que un buen ejemplo de boxeo en c # ocurre en las colecciones no genéricas como ArrayList .

Un ejemplo sería cuando un método toma un parámetro de objeto y se debe pasar un tipo de valor.

A continuación hay algunos ejemplos de boxeo / unboxing

ArrayList ints = new ArrayList();
myInts.Add(1); // boxing
myInts.Add(2); // boxing

int myInt = (int)ints [0]; // unboxing

Console.Write("Value is {0}", myInt); // boxing

Una de las situaciones en que esto sucede es, por ejemplo, si tiene un método que espera un parámetro de tipo de objeto y está pasando uno de los tipos primitivos, int por ejemplo. O si define el parámetro como 'ref' de tipo int.

El código

int x = 42;
Console.Writeline("The value of x is {0}", x );

en realidad encajona y desempaqueta porque Writeline hace un int lanzamiento dentro. Para evitar esto, puedes hacer

int x = 42;
Console.Writeline("The value of x is {0}", x.ToString());

¡Cuidado con los errores sutiles!

Puede declarar sus propios tipos de valor declarando su propio tipo como struct. Imagine que declara un ArrayList con muchas propiedades y luego coloca algunas instancias dentro de un []. Esto los encajona, por supuesto. Ahora haga referencia a uno a través del operador readonly, convirtiéndolo en el tipo y establezca una propiedad. Simplemente establece una propiedad en una copia . El que está en <=> todavía no se ha modificado.

Por esta razón, los tipos de valores siempre deben ser inmutables, es decir, hacer que todas las variables miembro <=> de modo que solo puedan establecerse en el constructor y no tengan ningún tipo mutable como miembros.

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