Pergunta

Há casos em que uma instância de uma Tipo de valor tem de ser tratado como um instância de um tipo de referência. Para situações como esta, um tipo de valor exemplo pode ser convertido numa Tipo de referência por meio de um exemplo processo chamado de boxe. Quando um valor Tipo de exemplo é embalado, o armazenamento é alocado no heap ea valor da instância é copiado para que espaço. Uma referência para este armazenamento é colocado na pilha. O valor em caixa É um objecto, um tipo de referência que contém o conteúdo do valor tipo de instância.

do .NET Entendimento Common Type System

Na Wikipedia há um exemplo para Java. Mas em C #, que são alguns casos em que um teria de caixa um tipo de valor? Ou seria uma pergunta melhor / semelhante ser, por que um quer para armazenar um tipo de valor na pilha (caixa), em vez de na pilha?

Foi útil?

Solução

Em geral, você normalmente vai querer evitar boxe seus tipos de valor.

No entanto, há ocorrências raros onde isso é útil. Se você precisa para atingir o quadro 1.1, por exemplo, você não terá acesso às coleções genéricas. Qualquer uso das coleções em .NET 1.1 exigiria tratar o seu tipo de valor como um System.Object, que faz com que o boxe / unboxing.

Há ainda casos para que isso seja útil em .NET 2.0+. Toda vez que você quer tirar proveito do fato de que todos os tipos, incluindo tipos de valor, pode ser tratado como um objeto diretamente, você pode precisar usar o boxe / unboxing. Isso pode ser útil às vezes, uma vez que permite que você salve qualquer tipo em uma coleção (usando objeto em vez de T em uma coleção genérica), mas, em geral, é melhor evitar isso, como você está perdendo a segurança de tipos. O único caso em que o boxe frequentemente ocorre, porém, é quando você está usando reflexão -. Muitas das chamadas na reflexão exigirá boxing / unboxing quando se trabalha com tipos de valor, uma vez que o tipo não é conhecido antecipadamente

Outras dicas

Há quase nunca é uma boa razão para a caixa deliberadamente um tipo de valor. Quase sempre, a razão para a caixa um tipo de valor é armazená-lo em alguma coleção que não é tipo conscientes. O velho ArrayList , por exemplo, é uma coleção de objectos, que são os tipos de referência. A única maneira de coletar, dizer, inteiros, é a caixa-los como objetos e passá-las para ArrayList.

Hoje em dia, nós temos coleções genéricas, por isso este é um problema menor.

Boxe geralmente acontece automaticamente em .NET quando eles têm que; muitas vezes quando você passa um tipo de valor a algo que espera um tipo de referência. Um exemplo comum é string.Format (). Quando você passar tipos de valores primitivos com este método, eles são embalados como parte da chamada. Assim:

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

Este ilustra um cenário simples, onde um tipo de valor (x) é automaticamente encaixotado para ser passada para um método que prevê um objecto. Geralmente, você quer evitar os tipos de valor de boxe quando possível ... mas em alguns casos é muito útil.

Em um aparte interessante, quando você usa os genéricos no .NET, tipos de valor não são encaixotados quando usados ??como parâmetros ou membros do tipo. O que torna os genéricos mais eficientes do que o código C # mais velhos (como ArrayList) que tudo tratar como {} objeto a ser tipo agnóstico. Isso acrescenta mais uma razão para usar coleções genéricas, como List<T> ou Dictionary<T,K> sobre ArrayList ou Hashtable.

Eu recomendo que você 2 nice artigos 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

Aqui está a citação que eu concordo 100% com

Usando a pilha para moradores de valor Tipo é apenas uma otimização que o CLR executa em seu nome. A característica relevante dos tipos de valor é que eles têm a semântica de ser copiado por valor, não que, por vezes, sua desatribuição pode ser optimizado pela o tempo de execução.

Em 99% desenvolvedores de aplicativos não deve se preocupar porque os tipos de valor são na pilha e não na pilha e o ganho de desempenho poderia temos aqui. Juts tem em mente regras muito simples:

  1. Evite boxing / unboxing não quando necessário, use coleções de genéricos. A maioria dos problemas não quando ocorre definir seus próprios tipos, mas quando você usar tipos existentes inproperly (Definido pela Microsoft ou o seu colegas)
  2. Faça seus tipos de valor simples. Se você precisa ter um struct com 10-20 campos, suponho you'ld melhor criar uma classe. Imagine tudo que os campos serão copiados cada vez quando, ocasionalmente, passá-lo um função por valor ...
  3. Eu não acho que é muito útil ter tipos de valor com tipo de referência campos dentro. Como struct com Cordas e objetos campos.
  4. Defina o tipo que você precisa, dependendo necessária funcionalidade, não sobre onde ele deve ser armazenado. structs têm funcionalidade limitada para comparar aulas, por isso, se struct não pode fornecer a funcionalidade necessária, como construtor padrão, definir classe.
  5. Se algo pode executar qualquer ações com os dados de outros tipos, que geralmente é definido como um classe. Para operações structs com diferentes tipos devem ser definidos somente se você pode lançar um tipo de outro. Digamos que você pode adicionar int para dobrar porque você pode lançar int para duplo.
  6. Se algo deve ser apátrida, é uma classe.
  7. tipos
  8. Quando você está hesitando, referência utilização. : -)

Todas as regras permite exclusões em casos especiais, mas não tente over-otimizar.

P.S. Eu conheci alguns desenvolvedores ASP.NET com 2-3 anos de experiência que não sabe a diferença entre a pilha e heap. :-( eu não iria contratar uma pessoa se eu sou um entrevistador, mas não por causa de boxe / unboxing poderia ser um gargalo em qualquer um dos sites de ASP.NET que eu já vi.

Eu acho que um bom exemplo de boxe em c # ocorre nas coleções não-genéricos como ArrayList .

Um exemplo seria quando um método leva um parâmetro de objeto e um tipo de valor deve ser passado.

Abaixo está alguns exemplos de boxe / 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

Uma das situações quando isso acontece é, por exemplo, se você tem método que esperar parâmetro do tipo de objeto e você está passando em um dos tipos primitivos, int por exemplo. Ou se você definir parâmetro como 'ref' do tipo int.

O código

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

na verdade, caixas e unboxes porque Writeline faz um interior int elenco. Para evitar isso, você poderia fazer

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

Cuidado com os erros sutis!

Você pode declarar seus próprios tipos de valor, declarando seu próprio tipo como struct. Imagine que você declarar um struct com muitas propriedades e, em seguida, colocar alguns casos dentro de um ArrayList. Este caixas deles, é claro. Agora referência a um através do operador [], lançando-a por tipo e definir uma propriedade. Você apenas definir uma propriedade em um cópia . O do ArrayList ainda não foi modificado.

Por esta razão, os tipos de valor deve ser sempre imutável, ou seja, fazer todas as variáveis ??de membro readonly de modo que eles só podem ser definidas no construtor e não têm quaisquer tipos mutáveis ??como membros.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top