Estive programando em C # e Java recentemente e estou curioso para saber onde o melhor lugar é inicializar meus campos de classe.
Devo fazê-lo na declaração ?:
public class Dice
{
private int topFace = 1;
private Random myRand = new Random();
public void Roll()
{
// ......
}
}
ou em um construtor ?:
public class Dice
{
private int topFace;
private Random myRand;
public Dice()
{
topFace = 1;
myRand = new Random();
}
public void Roll()
{
// .....
}
}
Estou realmente curioso sobre o que alguns de vocês veteranos acham que é a melhor prática. Eu quero ser consistente e seguir uma abordagem.
Respostas:
Minhas regras:
null
,false
,0
,0.0
...).fonte
default(T)
é sempre o valor que possui uma representação binária interna de0
.foreach
loop com "isso repete o seguinte para todos os itens da lista", não precisamos reajustar constantemente os valores padrão do C #. Também não precisamos fingir que o C # possui semântica não inicializada. Como a ausência de um valor tem um significado claro, é bom deixar de fora. Se for ideal para ser explícito, você sempre deve usá-lonew
ao criar novos delegados (como era necessário em C # 1). Mas quem faz isso? A linguagem é projetada para codificadores conscienciosos.Em C #, isso não importa. Os dois exemplos de código que você fornece são totalmente equivalentes. No primeiro exemplo, o compilador C # (ou é o CLR?) Construirá um construtor vazio e inicializará as variáveis como se estivessem no construtor (há uma leve nuance sobre isso que Jon Skeet explica nos comentários abaixo). Se já houver um construtor, qualquer inicialização "acima" será movida para a parte superior.
Em termos de melhores práticas, o primeiro é menos propenso a erros do que o último, pois alguém poderia facilmente adicionar outro construtor e esquecer de encadear.
fonte
A semântica do C # difere um pouco do Java aqui. Em C #, a atribuição na declaração é realizada antes de chamar o construtor da superclasse. Em Java, isso é feito imediatamente após o qual permite que 'this' seja usado (particularmente útil para classes internas anônimas) e significa que a semântica das duas formas realmente corresponde.
Se puder, torne os campos finais.
fonte
Eu acho que há uma ressalva. Uma vez cometi esse erro: dentro de uma classe derivada, tentei "inicializar na declaração" os campos herdados de uma classe base abstrata. O resultado foi que existiam dois conjuntos de campos, um é "base" e outro são os recém-declarados, e me custou algum tempo para depurar.
A lição: para inicializar campos herdados , você faria isso dentro do construtor.
fonte
derivedObject.InheritedField
, ele está se referindo à sua base ou à derivada?Assumindo o tipo no seu exemplo, definitivamente prefira inicializar os campos no construtor. Os casos excepcionais são:
Eu sempre penso na lista de campos na parte superior de uma classe como o índice (o que está contido aqui, não como é usado) e o construtor como a introdução. Métodos, é claro, são capítulos.
fonte
E se eu te contar, depende?
Em geral, inicializo tudo e faço de maneira consistente. Sim, é excessivamente explícito, mas também é um pouco mais fácil de manter.
Se estamos preocupados com o desempenho, bem, eu inicializo apenas o que precisa ser feito e o coloco nas áreas que oferece mais retorno.
Em um sistema de tempo real, questiono se preciso mesmo da variável ou constante.
E em C ++, costumo fazer quase nenhuma inicialização em qualquer lugar e movo-a para uma função Init (). Por quê? Bem, em C ++, se você está inicializando algo que pode gerar uma exceção durante a construção do objeto, você se abre para vazamentos de memória.
fonte
Existem muitas e várias situações.
Eu só preciso de uma lista vazia
A situação está clara. Eu só preciso preparar minha lista e impedir que uma exceção seja lançada quando alguém adicionar um item à lista.
Eu sei os valores
Sei exatamente quais valores quero ter por padrão ou preciso usar outra lógica.
ou
Lista vazia com valores possíveis
Às vezes, espero uma lista vazia por padrão, com a possibilidade de adicionar valores por meio de outro construtor.
fonte
Em Java, um inicializador com a declaração significa que o campo é sempre inicializado da mesma maneira, independentemente de qual construtor é usado (se você tiver mais de um) ou dos parâmetros de seus construtores (se eles tiverem argumentos), embora um construtor possa posteriormente altere o valor (se não for final). Portanto, o uso de um inicializador com uma declaração sugere ao leitor que o valor inicial é o valor que o campo possui em todos os casos , independentemente de qual construtor é usado e independentemente dos parâmetros passados para qualquer construtor. Portanto, use um inicializador com a declaração apenas se, e sempre se, o valor para todos os objetos construídos for o mesmo.
fonte
O design do C # sugere que a inicialização em linha é preferida ou não seria no idioma. Sempre que você pode evitar uma referência cruzada entre lugares diferentes no código, geralmente está melhor.
Há também a questão da consistência com a inicialização do campo estático, que precisa estar alinhado para obter o melhor desempenho. As diretrizes de design de estrutura para o design de construtores dizem o seguinte:
"Considerar" neste contexto significa fazê-lo, a menos que haja uma boa razão para não fazê-lo. No caso de campos estáticos do inicializador, um bom motivo seria se a inicialização fosse muito complexa para ser codificada em linha.
fonte
Ser consistente é importante, mas esta é a pergunta que você deve fazer: "Tenho um construtor para mais alguma coisa?"
Normalmente, estou criando modelos para transferências de dados que a própria classe não faz nada além de funcionar como alojamento para variáveis.
Nesses cenários, geralmente não tenho métodos ou construtores. Seria tolo para mim criar um construtor com o objetivo exclusivo de inicializar minhas listas, especialmente porque posso inicializá-las de acordo com a declaração.
Então, como muitos outros disseram, isso depende do seu uso. Mantenha as coisas simples e não faça nada a mais que você não precise.
fonte
Considere a situação em que você possui mais de um construtor. A inicialização será diferente para os diferentes construtores? Se eles serão os mesmos, por que repetir para cada construtor? Isso está de acordo com a instrução kokos, mas pode não estar relacionado aos parâmetros. Digamos, por exemplo, que você queira manter uma bandeira que mostre como o objeto foi criado. Em seguida, esse sinalizador seria inicializado de maneira diferente para diferentes construtores, independentemente dos parâmetros do construtor. Por outro lado, se você repetir a mesma inicialização para cada construtor, deixa a possibilidade de alterar (sem querer) o parâmetro de inicialização em alguns construtores, mas não em outros. Portanto, o conceito básico aqui é que o código comum deve ter um local comum e não ser potencialmente repetido em locais diferentes.
fonte
Há um pequeno benefício de desempenho ao definir o valor na declaração. Se você configurá-lo no construtor, ele está sendo configurado duas vezes (primeiro para o valor padrão e depois redefinido no ctor).
fonte
Normalmente, tento que o construtor não faça nada além de obter as dependências e inicializar os membros da instância relacionados com eles. Isso facilitará sua vida se você quiser testar suas aulas.
Se o valor que você irá atribuir a uma variável de instância não for influenciado por nenhum dos parâmetros que você passará para o construtor, atribua-o no momento da declaração.
fonte
Não é uma resposta direta à sua pergunta sobre as melhores práticas, mas um ponto de atualização importante e relacionado é que, no caso de uma definição de classe genérica, deixe no compilador a inicialização com valores padrão ou temos que usar um método especial para inicializar campos aos valores padrão (se isso for absolutamente necessário para a legibilidade do código).
E o método especial para inicializar um campo genérico com seu valor padrão é o seguinte:
fonte
Quando você não precisa de alguma lógica ou manipulação de erros:
Quando você precisar de alguma lógica ou manipulação de erros:
Em https://docs.oracle.com/javase/tutorial/java/javaOO/initial.html .
fonte