Qual é o melhor para estruturas / classs de armazenamento de dados?

Temos visto muita discussão em SO sobre a class vs struct em c #. Principalmente terminou com conclusões dizendo que é uma alocação de memory heap / pilha . E recomendando usar estruturas em estruturas de dados pequenas .

Agora eu tenho uma situação para decidir o armazenamento de dados simples entre essas duas opções. Atualmente em nosso aplicativo temos milhares de classs, apenas atua como simples repositorys de dados (somente campos públicos expostos) e passaram entre diferentes módulos e serviços.

De acordo com o meu entendimento, senti que é melhor seguir em frente com as classs struct em vez das razões de desempenho. Porque estas são estruturas de dados simples, apenas agem como armazenamentos de dados.

Antes de prosseguir com isso, preciso de alguns conselhos de especialistas das pessoas que passaram por essa luta.

  • meu entendimento é correto?
  • Eu vi a maioria dos ORMs ter classs como armazenamentos de dados. Então eu duvido que deveria haver uma razão para ir em frente com classs em vez de estruturas. o que seria aquilo?

Eu faria a escolha com base nos seguintes critérios

  • tipo de referência vs semântica do tipo de valor. Se 2 objects forem iguais apenas se forem o mesmo object, isso indica semântica do tipo de referência => class. Se o valor de seus membros define igualdade (por exemplo, 2 DateTimes são iguais se ambos representam o mesmo ponto no tempo, mesmo que sejam 2 objects distintos), semântica do tipo de valor => struct
  • Pegada de memory do object. Se o object é enorme e freqüentemente alocado, torná-lo um struct consumiria a pilha muito mais rápido, portanto, eu prefiro tê-lo como uma class. Pelo contrário, prefiro evitar a penalidade de GC para tipos de valor pequeno; daí torná-los uma estrutura.
  • você pode tornar o object imutável? Eu acho ótimas estruturas para ‘objects de valor’ – do livro DDD.
  • Você enfrentaria alguma penalidade de unboxing de boxe com base no uso desse object? Se sim, vá para a aula.

as estruturas devem ser definidas como imutáveis ​​onde nas classs não devem. Se você acha que seus objects serão pequenos e imutáveis, você pode ir em frente fazendo deles estruturas ou então deixá-los ser classs.

Uma vantagem muito legal, não tão bem conhecida de Structs over Classes, é que há uma implementação automática de GetHashcode e Equals em structs.
Isso é bastante útil quando as chaves são necessárias para dictionarys

A implementação de struct de GetHashcode e Equals é baseada no conteúdo binário das instâncias de struct + reflection para os membros de referência (como membros String e outras instâncias de classs)

Portanto, o código a seguir funciona para GethashCode / Equals:

 public struct Person { public DateTime Birthday { get; set; } public int Age{ get; set; } public String Firstname { get; set; } } class Program { static void Main(string[] args) { Person p1 = new Person { Age = 44, Birthday = new DateTime(1971, 5, 24), Firstname = "Emmanuel" }; Person p2 = new Person { Age = 44, Birthday = new DateTime(1971, 5, 24), Firstname = "Emmanuel" }; Debug.Assert(p1.Equals(p2)); Debug.Assert(p1.GetHashCode() == p2.GetHashCode()); } } 

Ambas as afirmações são bem-sucedidas quando Person é uma struct. Ambas as asserções falham se Person for uma class em vez de uma struct

Referência: https://msdn.microsoft.com/pt-BR/library/2dts52z7%28v=vs.110%29.aspx

Atenciosamente, melhor codificação

Eu nunca consigo me lembrar, exatamente como as estruturas são diferentes, mas elas são. De maneiras sutis. De fato, às vezes eles vêm e mordem você.

Assim. A menos que você saiba o que está fazendo, apenas siga as aulas.

Eu sei que isso soa um pouco novato. Eu sei que agora devo ir e procurar as diferenças e mostrá-las aqui – mas isso já foi feito por outros. Tudo o que estou dizendo é que adicionar um tipo diferente de objects cria uma carga semântica, um pouco de complexidade extra que você deve considerar cuidadosamente.

Se bem me lembro, um dos maiores problemas é a semântica do valor das structs: Passá-las irá resultar em objects diferentes (conforme eles são passados ​​por valor). Se você alterar algum campo em um lugar, cuidado com o fato de que em todos os outros lugares o campo não foi alterado! É por isso que todos estão recomendando a imutabilidade para estruturas!

EDIT: Para o caso que você está descrevendo, structs não vai funcionar !

Um object de class tem a vantagem de ser possível passar uma referência a ele, com o escopo e o tempo de vida de tal referência sendo ilimitados se atingirem o código externo. Uma estrutura tem a vantagem de que, embora seja possível passar referências curtas a elas, não é possível passar referências perpétuas promíscuas. Isso ajuda a evitar ter que se preocupar se tais referências existem.

Algumas pessoas sugeriram que os detentores de dados que são mutáveis ​​não devem ser estruturas. Eu discordo enfaticamente. As entidades que existem com a finalidade de armazenar dados devem, em muitos casos, ser estruturas, especialmente se forem mutáveis. Eric Lippert postou várias vezes que ele considera os tipos de valores mutáveis ​​como evil (procure nas tags “mutable” e “struct”). É certamente verdade que o .net permite que certas coisas sejam feitas com estruturas mutáveis ​​que ele não deveria, e não permite convenientemente algumas coisas que deveria, mas estruturas POD (“Plain Old Data”) que não possuem methods mutantes, mas, em vez disso, expor seu estado inteiro por meio de campos públicos, têm uma consistência muito útil em seu comportamento, que não é compartilhada com nenhum outro tipo de dados. Usar uma estrutura POD pode confundir alguém que não esteja familiarizado com o funcionamento deles, mas tornará o programa muito mais legível para qualquer um que o faça.

Considere, por exemplo, o código a seguir, assumindo que EmployeeInfoStruct contém nada além de tipos de valor e tipos de class imutáveis como String:

 [employeeInfoStruct é uma estrutura que contém o campo a seguir]
 public Decimal YearlyBonus;

 [someEmployeeContainer é uma instância de uma class que inclui o seguinte método]
 EmployeeInfoStruct GetEmployeeInfo (id da cadeia);  // Apenas a assinatura - o código é imaterial

 [algum outro método usa o seguinte código]
 EmployeeInfoStruct anEmployee = someEmployeeContainer.GetEmployeeInfo ("123-45-6789");
 anEmployee.YearlyBonus + = 100;

Eric Lippert reclama que o código acima alterará o valor em anEmployee, mas essa alteração não terá nenhum efeito no contêiner. Eu sugeriria que é uma coisa boa – qualquer um que saiba como as estruturas funcionam pode olhar o código acima e saber que escrever em uma variável struct afetará essa variável, mas não afetará mais nada a menos que o programa use algum outro método (talvez SetEmployeeInfo) para armazenar essa variável em algum lugar.

Agora substitua EmployeeInfoStruct por EmployeeInfoClass, que possui uma propriedade de leitura / gravação do tipo YearlyBonus. Usando apenas as informações acima, o que se pode dizer sobre o relacionamento entre as gravações em someEmployeeContainer e anEmployee? Dependendo das implementações da class do anEmployee (que, a menos que EmployeeInfoClass esteja lacrado, pode ou não ser realmente EmployeeInfoClass) e someEmployeeContainer, o relacionamento entre os objects poderia ser qualquer coisa. Escreve para um poder:

  1. Não tem efeito sobre o outro
  2. Atualize o outro na moda ‘natural’
  3. Corrompido o outro de alguma maneira arbitrária

Com estruturas contendo nada além de campos de tipos de valor ou classs imutáveis , a semântica sempre será a # 1. Não é preciso olhar o código da própria estrutura, nem o código do contêiner, para saber disso. Por outro lado, se o anEmployee.Salary ou o someEmployeeContainer.GetEmployee for virtual, é impossível saber realmente qual será a semântica.

É importante observar que, se as estruturas forem grandes, passá-las por valor ou retorná-las de funções pode ser caro. Geralmente, é melhor passar structs grandes como parâmetros ref quando possível. Embora as collections internas realmente não façam um bom trabalho de facilitar esse uso, ele pode tornar o uso de um struct de centenas de bytes mais barato do que usar uma class.

O comentário sobre as estruturas sendo imutáveis ​​está correto. E é aí que ele pode te morder. Você pode definir estruturas com definidores de campo, mas quando você altera um valor de campo, uma nova instância é criada. Então, se você mantiver uma referência ao object antigo, ele ainda fará referência ao valor antigo. Eu não gosto de usar stucts mutáveis ​​por este motivo, pois isso pode produzir bugs sutis e complexos (especialmente se você usar instruções compostas complexas).

Por outro lado, há muitas boas razões para usar classs com estado imutável também (pense em string).

Lembro-me de um conselho dado no MSDN que struct não deve ser maior que 16 ou 21 bytes. Procurando pelo link, mas não consegue encontrá-lo ainda.

A principal implicação foi que, uma vez que você tenha uma string no seu tipo de dados, crie uma class sem pensar. Caso contrário, a estrutura não deve aguentar muito.

Eu acho que você tem a ideia certa. Estruturas são feitas para imitar tipos de dados. Eles são baseados em valores não baseados em referência. Se você olhar a documentação do MSDN para a maioria das classs de dados de base (int, double, decimal, ect.) Elas são todas baseadas em structs. Dito isto, no entanto, as estruturas não devem ser usadas em demasia pelo mesmo motivo. A sala para armazenar tudo na estrutura é alocada assim que é instanciada, onde as classs apenas alocam espaço para uma referência a tudo dentro. Se os dados estiverem em pedaços pequenos o suficiente, onde isso não é um problema, as estruturas são o caminho a percorrer. Se isso é um problema, vá com classs. Se você não sabe, talvez seja melhor ficar com o que você está familiarizado.

Se você tiver requisitos de baixa latência e MUITOS objects compactos, as coletas de lixo podem ser um problema. Nesse caso, struct pode ser muito útil porque o coletor de lixo não precisa varrer uma hierarquia de tipos de valor se os tipos de valor não contiverem nenhum tipo de referência.

Você pode encontrar uma referência aqui: http://00sharp.wordpress.com/2013/07/03/a-case-for-the-struct/