Pergunta

Eu li todas as perguntas relacionadas a este tópico, e todas dão razões pelas quais um construtor padrão em um struct Não está disponível em C#, mas ainda não encontrei ninguém que sugere um curso geral de ação quando confrontado com essa situação.

A solução óbvia é simplesmente converter o struct para um class e lidar com as consequências.

Existem outras opções para mantê -lo como um struct?

Eu encontrei essa situação com um de nossos objetos internos de API de comércio. O designer o converteu de um class para um struct, e agora o construtor padrão (que era privado antes) deixa o objeto em um estado inválido.

Eu pensei que se vamos manter o objeto como um struct, um mecanismo para verificar a validade do estado deve ser introduzido (algo como um IsValid propriedade). Recebi muita resistência e uma explicação de "quem usa a API não deve usar o construtor padrão", um comentário que certamente levantou minhas sobrancelhas. (Nota: o objeto em questão é construído "adequadamente" através de métodos estáticos de fábrica, e todos os outros construtores são internal.)

Todo mundo está simplesmente convertendo seu structs para classES nesta situação sem pensar segundo?

Editar: eu gostaria de ver algumas sugestões sobre como manter esse tipo de objeto como um struct - O objeto em questão acima é muito mais adequado como um struct do que como um class.

Foi útil?

Solução

Para struct, você projeta o tipo para que a instância construída padrão (campos todos zero) seja um estado válido. Você não [não deve] use arbitrariamente struct ao invés de class Sem um bom motivo - não há nada de errado em usar um tipo de referência imutável.

Minhas sugestões:

  • Verifique se o motivo do uso de um struct é válido (um perfilador [real] revelou problemas de desempenho significativos resultantes da alocação pesada de um objeto muito leve).
  • Projete o tipo para que a instância construída padrão seja válida.
  • Se o design do tipo for ditado por restrições de interoperas nativas/com, embrulhe a funcionalidade e não exponha o struct Fora do invólucro (tipo aninhado privado). Dessa forma, você pode documentar e verificar facilmente o uso adequado dos requisitos de tipo restrito.

Outras dicas

A razão para isso é que uma estrutura (uma instância do sistema.valuetype) é tratada especialmente pelo CLR: é inicializada com todos os campos sendo 0 (ou padrão). Você nem precisa criar um - basta declará -lo. É por isso que os construtores padrão são necessários.

Você pode contornar isso de duas maneiras:

  1. Crie uma propriedade como o ISValid para indicar se é uma estrutura válida, como você indica e
  2. no .NET 2.0 Considere usar o Nullableu003CT> Para permitir uma estrutura não inicializada (nula).

Alterar a estrutura para uma classe pode ter algumas consequências muito sutis (em termos de uso de memória e identidade de objetos que surgem mais em um ambiente multithread) e não-sutil, mas difícil de depurar o NullReferenceExceptions para objetos não inicializados.

A razão pela qual não há possibilidade de definir um construtor padrão é ilustrado pela seguinte expressão:

new MyStruct[1000];

Você tem 3 opções aqui

  1. chamando o construtor padrão 1000 vezes, ou
  2. Criando dados corrompidos (observe que uma estrutura pode conter referências; se você não inicializar ou emanhar a referência, poderá acessar a memória arbitrária) ou
  3. em branco a memória alocada com zeros (no nível do byte).

.NET faz o mesmo para estruturas e classes: campos e elementos da matriz são apagados com zeros. Isso também recebe um comportamento mais consistente entre estruturas e classes e nenhum código inseguro. Ele também permite que a estrutura .NET não seja especializada em algo como new byte[1000].

E esse é o construtor padrão para estruturas .NET exige e cuida de si mesma: zero todos os bytes.

Agora, para lidar com isso, você tem algumas opções:

  • Adicione uma propriedade AM-i-inicializada à estrutura (como HasValue sobre Nullable).
  • Permita que a estrutura zero seja um valor válido (como 0 é um valor válido para um decimal).
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top