No .NET, existem duas categorias de tipos, tipos de referência e tipos de valor .
Estruturas são tipos de valor e classes são tipos de referência .
A diferença geral é que um tipo de referência vive no heap e um tipo de valor vive inline, ou seja, onde quer que sua variável ou campo seja definido.
Uma variável que contém um tipo de valor contém todo o valor do tipo de valor. Para uma estrutura, isso significa que a variável contém toda a estrutura, com todos os seus campos.
Uma variável que contém um tipo de referência contém um ponteiro ou uma referência a outro lugar na memória em que o valor real reside.
Isso tem um benefício, para começar:
- tipos de valor sempre contêm um valor
- tipos de referência podem conter uma referência nula , o que significa que eles não se referem a nada no momento
Internamente, os tipos de referência são implementados como ponteiros e, sabendo que, e como a atribuição de variáveis funciona, existem outros padrões de comportamento:
- copiar o conteúdo de uma variável de tipo de valor para outra variável, copia todo o conteúdo para a nova variável, tornando as duas distintas. Em outras palavras, após a cópia, as alterações em uma não afetam a outra
- copiar o conteúdo de uma variável de tipo de referência para outra variável, copia a referência, o que significa que agora você tem duas referências à mesma em outro lugar para armazenamento dos dados reais. Em outras palavras, após a cópia, alterar os dados em uma referência também afetará a outra, mas apenas porque você realmente está apenas olhando para os mesmos dados nos dois lugares
Quando você declara variáveis ou campos, veja como os dois tipos diferem:
- variável: o tipo de valor vive na pilha, o tipo de referência vive na pilha como um ponteiro para algum lugar na memória de pilha onde a memória real vive (embora observe a série de artigos de Eric Lipperts: A pilha é um detalhe de implementação .)
- classe / estrutura-campo: o tipo de valor vive completamente dentro do tipo, o tipo de referência vive dentro do tipo como um ponteiro para algum lugar na memória de pilha onde a memória real vive.
Um breve resumo de cada um:
Somente aulas:
Somente estruturas:
Classes e estruturas:
fonte
c# struct memory overhead
e encontrei essa resposta de Hans Passant que diz que não, esse também não é o caso. Então o que você quer dizer?class
memória gerenciada (tratadas pelo coletor de lixo), enquanto instâncias destruct
não são .No .NET, as declarações struct e class diferenciam tipos de referência e tipos de valor.
Quando você passa um tipo de referência, existe apenas um realmente armazenado. Todo o código que acessa a instância está acessando o mesmo.
Quando você passa um tipo de valor, cada um é uma cópia. Todo o código está trabalhando em sua própria cópia.
Isso pode ser mostrado com um exemplo:
Para uma classe isso seria diferente
Classes não podem ser nada - a referência pode apontar para um nulo.
Estruturas são o valor real - elas podem estar vazias, mas nunca nulas. Por esse motivo, as estruturas sempre têm um construtor padrão sem parâmetros - elas precisam de um 'valor inicial'.
fonte
Diferença entre estruturas e classes:
fonte
Da escolha da Microsoft entre classe e estrutura ...
fonte
Além de todas as diferenças descritas nas outras respostas:
Se você estiver após um vídeo explicando todas as diferenças, consulte a Parte 29 - Tutorial em C # - Diferença entre classes e estruturas em C # .
fonte
Instâncias de classes são armazenadas no heap gerenciado. Todas as variáveis que contêm uma instância são simplesmente uma referência à instância no heap. Passar um objeto para um método resulta em uma cópia da referência, não no próprio objeto.
Estruturas (tecnicamente, tipos de valor) são armazenadas onde quer que sejam usadas, como um tipo primitivo. O conteúdo pode ser copiado pelo tempo de execução a qualquer momento e sem chamar um construtor de cópias personalizado. Passar um tipo de valor para um método envolve copiar o valor inteiro, novamente sem chamar nenhum código personalizável.
A distinção é aprimorada pelos nomes C ++ / CLI: "ref class" é uma classe conforme descrito primeiro, "value class" é uma classe conforme descrito em segundo. As palavras-chave "class" e "struct", usadas pelo C #, são simplesmente algo que deve ser aprendido.
fonte
fonte
Estrutura vs Classe
Uma estrutura é um tipo de valor, portanto, é armazenada na pilha, mas uma classe é um tipo de referência e é armazenada no heap.
Uma estrutura não suporta herança e polimorfismo, mas uma classe suporta ambos.
Por padrão, todos os membros da estrutura são públicos, mas os membros da classe são por natureza particulares.
Como uma estrutura é um tipo de valor, não podemos atribuir nulo a um objeto struct, mas não é o caso de uma classe.
fonte
Para adicionar às outras respostas, há uma diferença fundamental que vale a pena notar, e é assim que os dados são armazenados nas matrizes, pois isso pode ter um efeito importante no desempenho.
Portanto, uma matriz de estruturas se parece com isso na memória
[struct][struct][struct][struct][struct][struct][struct][struct]
Enquanto uma matriz de classes se parece com isso
[pointer][pointer][pointer][pointer][pointer][pointer][pointer][pointer]
Com uma matriz de classes, os valores nos quais você está interessado não são armazenados na matriz, mas em outros lugares da memória.
Para a grande maioria dos aplicativos, essa diferença realmente não importa, no entanto, no código de alto desempenho, isso afeta a localidade dos dados na memória e tem um grande impacto no desempenho do cache da CPU. O uso de classes quando você poderia / deveria ter usado estruturas aumentaria enormemente o número de falhas de cache na CPU.
A coisa mais lenta que uma CPU moderna faz não é triturar números, é buscar dados da memória e um acerto no cache L1 é muitas vezes mais rápido do que ler dados da RAM.
Aqui está um código que você pode testar. Na minha máquina, a iteração na matriz de classes leva ~ 3x mais tempo que a matriz struct.
fonte
Apenas para completá-lo, há outra diferença ao usar o
Equals
método, que é herdado por todas as classes e estruturas.Vamos dizer que temos uma classe e uma estrutura:
e no método Main, temos 4 objetos.
Então:
Portanto , as estruturas são adequadas para objetos numéricos, como pontos (salve as coordenadas xey). E as aulas são adequadas para outros. Mesmo que duas pessoas tenham o mesmo nome, altura, peso ..., ainda são duas pessoas.
fonte
Bem, para iniciantes, uma estrutura é passada por valor e não por referência. Estruturas são boas para estruturas de dados relativamente simples, enquanto as classes têm muito mais flexibilidade do ponto de vista arquitetural via polimorfismo e herança.
Outros provavelmente podem lhe dar mais detalhes do que eu, mas uso estruturas quando a estrutura que pretendo é simples.
fonte
Além da diferença básica do especificador de acesso, e das poucas mencionadas acima, gostaria de adicionar algumas das principais diferenças, incluindo algumas das mencionadas acima, com uma amostra de código com saída, que fornecerá uma idéia mais clara da referência e do valor
Estruturas:
Classe:
Amostra de código
Resultado
O valor inicial do objeto Struct é: 10
Método Inside Struct O valor Inside Method do Struct Object é: 20
Após o método, o valor da chamada de Struct Object é: 10
O valor inicial do objeto de classe é: 10
Método Inside Class O valor Inside Method do objeto Class é: 20
Após o método, o valor da chamada de Objeto de Classe é: 20
Aqui você pode ver claramente a diferença entre chamada por valor e chamada por referência.
fonte
Os eventos declarados em uma classe têm seu acesso + = e - = bloqueado automaticamente por meio de um bloqueio (isso) para torná-los seguros (os eventos estáticos são bloqueados no tipo da classe). Eventos declarados em uma estrutura não têm seu acesso + = e - = bloqueado automaticamente. Um bloqueio (isso) para uma estrutura não funcionaria, pois você só pode bloquear uma expressão de tipo de referência.
A criação de uma instância struct não pode causar uma coleta de lixo (a menos que o construtor direta ou indiretamente crie uma instância de tipo de referência), enquanto a criação de uma instância do tipo de referência pode causar a coleta de lixo.
Uma estrutura sempre tem um construtor padrão público interno.
Isso significa que uma estrutura é sempre instanciada, enquanto uma classe pode não ser, pois todos os seus construtores podem ser privados.
Uma estrutura não pode ter um destruidor. Um destruidor é apenas uma substituição de objeto. Finalize disfarçado e estruturas, sendo tipos de valor, não estão sujeitas à coleta de lixo.
Uma estrutura está implicitamente selada, uma classe não.
Uma estrutura não pode ser abstrata, uma classe pode.
Uma estrutura não pode chamar: base () em seu construtor, enquanto uma classe sem classe base explícita pode.
Uma estrutura não pode estender outra classe, uma classe pode.
Uma estrutura não pode declarar membros protegidos (por exemplo, campos, tipos aninhados) que uma classe pode.
Uma estrutura não pode declarar membros da função abstrata, uma classe abstrata pode.
Uma estrutura não pode declarar membros da função virtual, uma classe pode.
Uma estrutura não pode declarar membros selados da função, uma classe pode.
Uma estrutura não pode declarar substituir membros da função, uma classe pode.
A única exceção a essa regra é que uma estrutura pode substituir os métodos virtuais de System.Object, viz, Equals () e GetHashCode () e ToString ().
fonte
Object
, que conteria uma referência a uma cópia em caixa da estrutura.Como mencionado anteriormente: Classes são do tipo referência, enquanto Structs são do tipo valor, com todas as consequências.
Como regra geral, o Framework Design Guidelines recomenda o uso de Structs em vez de classes se:
fonte
Há um caso interessante do quebra-cabeça "classe versus estrutura" - situação em que você precisa retornar vários resultados do método: escolha qual usar. Se você conhece a história ValueTuple - você sabe que ValueTuple (struct) foi adicionado porque deveria ser mais eficaz que Tuple (classe). Mas o que isso significa em números? Dois testes: um é struct / class que possui 2 campos, outro com struct / class que possui 8 campos (com dimensão maior que 4 - classe deve se tornar mais eficaz que estrutura em termos de ticks de processador, mas é claro que a carga do GC também deve ser considerada )
PS Existe outra referência para o caso específico 'sturct ou classe com coleções': https://stackoverflow.com/a/45276657/506147
Teste de código:
fonte
Isso é verdade, no entanto, observe também que as estruturas do .NET 2 oferecem suporte a uma versão Nullable e o C # fornece algum açúcar sintático para facilitar o uso.
fonte
(object)(default(int?)) == null
que você não pode fazer com qualquer outro tipo de valor, porque há mais do que apenas açúcar acontecendo aqui. O único açúcar éint?
paraNullable<int>
.Toda variável ou campo de um tipo de valor primitivo ou tipo de estrutura mantém uma instância exclusiva desse tipo, incluindo todos os seus campos (público e privado). Por outro lado, variáveis ou campos de tipos de referência podem ser nulos ou podem se referir a um objeto armazenado em outro local, ao qual também pode existir qualquer número de outras referências. Os campos de uma estrutura serão armazenados no mesmo local que a variável ou o campo desse tipo de estrutura, que pode estar na pilha ou fazer parte de outro objeto de heap.
Criar uma variável ou campo de um tipo de valor primitivo o criará com um valor padrão; criar uma variável ou campo de um tipo de estrutura criará uma nova instância, criando todos os campos nela da maneira padrão. Criando uma nova instância de um tipo de referência começará criando todos os campos da maneira padrão e executando o código adicional opcional, dependendo do tipo.
Copiar uma variável ou campo de um tipo primitivo para outro copiará o valor. A cópia de uma variável ou campo do tipo de estrutura para outra copiará todos os campos (públicos e privados) da instância anterior para a última instância. Copiar uma variável ou campo do tipo de referência para outro fará com que o último se refira à mesma instância que o primeiro (se houver).
É importante observar que em algumas linguagens como C ++, o comportamento semântico de um tipo é independente de como é armazenado, mas isso não ocorre no .NET. Se um tipo implementa semântica de valor mutável, a cópia de uma variável desse tipo para outra copia as propriedades da primeira para outra instância, mencionada pela segunda, e o uso de um membro da segunda para fazer a mutação fará com que a segunda instância seja alterada. , mas não o primeiro. Se um tipo implementa semântica de referência mutável, copiar uma variável para outra e usar um membro do segundo para alterar o objeto afetará o objeto referido pela primeira variável; tipos com semântica imutável não permitem mutação; portanto, não importa semanticamente se a cópia cria uma nova instância ou cria outra referência à primeira.
No .NET, é possível que os tipos de valor implementem qualquer uma das semânticas acima, desde que todos os seus campos possam fazer o mesmo. Um tipo de referência, no entanto, só pode implementar semântica de referência mutável ou semântica imutável; tipos de valor com campos de tipos de referência mutáveis são limitados à implementação de semântica de referência mutável ou semântica híbrida estranha.
fonte