tl; dr - O usoChild
excessivoParent
é preferível no escopo local. Isso não apenas ajuda na legibilidade, mas também é necessário garantir que a resolução do método sobrecarregado funcione corretamente e ajude a permitir a compilação eficiente.
No escopo local,
Parent obj = new Child(); // Works
Child obj = new Child(); // Better
var obj = new Child(); // Best
Conceitualmente, trata-se de manter o máximo de informações de tipo possível. Se fizermos o downgrade para Parent
, estamos basicamente retirando informações de tipo que poderiam ter sido úteis.
Manter as informações completas sobre o tipo tem quatro vantagens principais:
- Fornece mais informações ao compilador.
- Fornece mais informações ao leitor.
- Código mais limpo e padronizado.
- Torna a lógica do programa mais mutável.
Vantagem 1: Mais informações para o compilador
O tipo aparente é usado na resolução do método sobrecarregado e na otimização.
Exemplo: Resolução de método sobrecarregado
main()
{
Parent parent = new Child();
foo(parent);
Child child = new Child();
foo(child);
}
foo(Parent arg) { /* ... */ } // More general
foo(Child arg) { /* ... */ } // Case-specific optimizations
No exemplo acima, ambas as foo()
chamadas funcionam , mas em um caso, obtemos a melhor resolução do método sobrecarregado.
Exemplo: Otimização do Compilador
main()
{
Parent parent = new Child();
var x = parent.Foo();
Child child = new Child();
var y = child .Foo();
}
class Parent
{
virtual int Foo() { return 1; }
}
class Child : Parent
{
sealed override int Foo() { return 2; }
}
No exemplo acima, as duas .Foo()
chamadas finalmente chamam o mesmo override
método que retorna 2
. Apenas, no primeiro caso, há uma pesquisa de método virtual para encontrar o método correto; essa pesquisa de método virtual não é necessária no segundo caso, uma vez que é desse método sealed
.
Agradecemos a @Ben, que forneceu um exemplo semelhante em sua resposta .
Vantagem 2: Mais informações para o leitor
Conhecer o tipo exato, ou seja Child
, fornece mais informações para quem está lendo o código, facilitando a visualização do que o programa está fazendo.
Claro, talvez não importa para o código real uma vez que ambos parent.Foo();
e child.Foo();
faz sentido, mas para alguém ver o código pela primeira vez, mais informações é simplesmente útil.
Além disso, dependendo do seu ambiente de desenvolvimento, o IDE pode ser capaz de fornecer dicas de ferramentas mais úteis e metadados sobre Child
a Parent
.
Vantagem 3: Código mais limpo e mais padronizado
A maioria dos exemplos de código C # que eu tenho visto ultimamente usa var
, o que é basicamente uma abreviação de Child
.
Parent obj = new Child(); // Sub-optimal
Child obj = new Child(); // Optimal, but anti-pattern syntax
var obj = new Child(); // Optimal, clean, patterned syntax "everyone" uses now
Ver uma var
declaração de não declaração simplesmente desaparece; se houver uma razão situacional para isso, incrível, mas, caso contrário, parece antipadrão.
// Clean:
var foo1 = new Person();
var foo2 = new Job();
var foo3 = new Residence();
// Staggered:
Person foo1 = new Person();
Job foo2 = new Job();
Residence foo3 = new Residence();
Vantagem 4: Lógica de programa mais mutável para prototipagem
As três primeiras vantagens foram as grandes; esse é muito mais situacional.
Ainda assim, para pessoas que usam código como outros usam o Excel, estamos constantemente alterando nosso código. Talvez a gente não precisa chamar um método único para Child
a presente versão do código, mas pode redirecionar ou refazer o código mais tarde.
A vantagem de um sistema de tipo forte é que ele nos fornece certos metadados sobre a lógica do programa, tornando as possibilidades mais aparentes. Isso é incrivelmente útil na criação de protótipos, por isso é melhor mantê-lo sempre que possível.
Sumário
O uso de Parent
bagunças na resolução do método sobrecarregado, inibe algumas otimizações do compilador, remove as informações do leitor e torna o código mais feio.
Usar var
é realmente o caminho a percorrer. É rápido, limpo, padronizado e ajuda o compilador e o IDE a fazer seu trabalho corretamente.
Importante : Esta resposta é sobreParent
vs.Child
no escopo local de um método. A questão deParent
vs.Child
é muito diferente para tipos de retorno, argumentos e campos de classe.