Escolher entre Classe e Struct

Observação

Este conteúdo é reimpresso com permissão da Pearson Education, Inc. de Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition. Essa edição foi publicada em 2008 e, desde então, o livro foi totalmente revisado na terceira edição. Algumas das informações nesta página podem estar desatualizadas.

Uma das decisões básicas de design que cada designer de estrutura enfrenta é se vai criar um tipo como uma classe (um tipo de referência) ou como um struct (um tipo de valor). Uma boa compreensão das diferenças no comportamento dos tipos de referência e tipos de valor é crucial para fazer essa escolha.

A primeira diferença entre tipos de referência e tipos de valor que consideraremos é que os tipos de referência são alocados no heap e coletados como lixo, enquanto que os tipos de valor são alocados na pilha ou em linha na contenção de tipos e desalocados quando a pilha desenrola ou quando seu tipo de contenção é desalocado. Portanto, alocações e desalocações de tipos de valor são, em geral, mais baratas do que alocações e desalocações de tipos de referência.

Em seguida, as matrizes de tipos de referência são alocadas fora de linha, significando que os elementos da matriz são apenas referências a instâncias do tipo de referência que residem no heap. As matrizes de tipos de valor são alocadas em linha, significando que os elementos da matriz são as instâncias reais do tipo de valor. Portanto, alocações e desalocações de matrizes de tipos de valor são muito mais baratas do que alocações e desalocações de matrizes de tipos de referência. Além disso, na maioria dos casos, as matrizes de tipos de valor apresentam uma localidade de referência muito melhor.

A próxima diferença está relacionada ao uso de memória. Os tipos de valor são encaixotados quando convertidos em um tipo de referência ou em uma das interfaces que implementam. Eles são desencaixotados quando convertidos de volta para o tipo de valor. Como as caixas são objetos alocados no heap e são coletados como lixo, o excesso de conversão boxing e conversão unboxing pode ter um impacto negativo no heap, no coletor de lixo e, basicamente, no desempenho do aplicativo. Por outro lado, nenhuma conversão boxing como tal ocorre à medida que os tipos de referência são convertidos. (Para obter mais informações, consulte Conversão boxing e Conversão unboxing.)

Em seguida, as atribuições de tipo de referência copiam a referência, enquanto as atribuições de tipo de valor copiam o valor inteiro. Portanto, as atribuições de tipos de referência grandes são mais baratas do que as atribuições de tipos de valor grandes.

Por fim, os tipos de referência são passados por referência, enquanto os tipos de valor são passados por valor. As alterações em uma instância de um tipo de referência afetam todas as referências que apontam para a instância. As instâncias de tipo de valor são copiadas quando são passadas por valor. Quando uma instância de um tipo de valor é alterada, é claro que isso não afeta nenhuma de suas cópias. Como as cópias não são criadas explicitamente pelo usuário, mas são criadas implicitamente quando os argumentos são passados ou os valores retornados são retornados, os tipos de valor que podem ser alterados podem ser confusos para muitos usuários. Portanto, os tipos de valor devem ser imutáveis.

Como regra geral, a maioria dos tipos em uma estrutura deve ser classes. Há, no entanto, algumas situações em que as características de um tipo de valor tornam mais apropriado usar structs.

✔️ CONSIDERE definir um struct em vez de uma classe se as instâncias do tipo forem pequenas e normalmente de curta duração ou se forem comumente incorporadas em outros objetos.

❌ EVITE definir um struct, a menos que o tipo tenha todas as características a seguir:

  • Representa logicamente um único valor, semelhante aos tipos primitivos (int, double etc.).

  • Tem um tamanho de instância inferior a 16 bytes.

  • É imutável.

  • Não precisará ser encaixotado com frequência.

Em todos os outros casos, você deve definir seus tipos como classes.

Portions © 2005, 2009 Microsoft Corporation. Todos os direitos reservados.

Reimpresso com permissão da Pearson Education, Inc. das Diretrizes de Design do Framework: convenções, linguagens e padrões para bibliotecas do .NET reutilizável, 2ª edição por Krzysztof Cwalina e Brad Abrams, publicado em 22 de outubro de 2008 por Addison-Wesley Professional como parte da série de desenvolvimento do Microsoft Windows.

Confira também