tl; dr - Używanie opcjiChild
overParent
jest lepsze w zakresie lokalnym. Pomaga to nie tylko w czytelności, ale także zapewnia prawidłowe działanie przeciążonej rozdzielczości metody i umożliwia wydajną kompilację.
W zakresie lokalnym
Parent obj = new Child(); // Works
Child obj = new Child(); // Better
var obj = new Child(); // Best
Koncepcyjnie chodzi o zachowanie jak największej ilości informacji o typie. Jeśli obniżymy doParent
, zasadniczo usuwamy informacje o typie, które mogłyby być przydatne.
Zachowanie pełnej informacji o typie ma cztery główne zalety:
- Dostarcza więcej informacji kompilatorowi.
- Zapewnia czytelnikowi więcej informacji.
- Czystszy, bardziej znormalizowany kod.
- Sprawia, że logika programu jest bardziej zmienna.
Zaleta 1: Więcej informacji dla kompilatora
Typ pozorny jest wykorzystywany przy przeładowaniu rozdzielczości i optymalizacji.
Przykład: Przeciążona rozdzielczość metody
main()
{
Parent parent = new Child();
foo(parent);
Child child = new Child();
foo(child);
}
foo(Parent arg) { /* ... */ } // More general
foo(Child arg) { /* ... */ } // Case-specific optimizations
W powyższym przykładzie oba foo()
wywołania działają , ale w jednym przypadku uzyskujemy lepszą rozdzielczość przeciążonej metody.
Przykład: optymalizacja kompilatora
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; }
}
W powyższym przykładzie oba .Foo()
wywołania ostatecznie wywołują tę samą override
metodę, która zwraca 2
. Po prostu w pierwszym przypadku istnieje wirtualne wyszukiwanie metod w celu znalezienia właściwej metody; to wyszukiwanie wirtualne metody nie jest potrzebne w drugim przypadku, ponieważ ta metoda jest sealed
.
Podziękowania dla @Ben, który podał podobny przykład w swojej odpowiedzi .
Zaleta 2: Więcej informacji dla czytelnika
Znajomość dokładnego typu, tj. Child
, Zapewnia więcej informacji każdemu, kto czyta kod, ułatwiając zobaczenie, co robi program.
Oczywiście, może to nie ma znaczenia, do rzeczywistego kodu ponieważ oba parent.Foo();
i child.Foo();
sensu, ale dla kogoś, widząc kodu po raz pierwszy, więcej informacji znajduje się po prostu pomocne.
Dodatkowo, w zależności od środowiska programistycznego, IDE może być w stanie dostarczyć bardziej pomocnych podpowiedzi i metadanych na temat Child
niż Parent
.
Zaleta 3: Czystszy, bardziej znormalizowany kod
Większość przykładów kodu C #, które ostatnio widziałem var
, jest w skrócie skrótem 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
Widząc var
oświadczenie o braku deklaracji po prostu wygląda; jeśli ma to uzasadnienie sytuacyjne, to świetnie, ale poza tym wygląda anty-wzór.
// 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();
Zaleta 4: Bardziej zmienna logika programu do prototypowania
Pierwsze trzy zalety były duże; ten jest o wiele bardziej sytuacyjny.
Jednak dla osób, które używają kodu tak jak inni używają Excela, stale zmieniamy nasz kod. Może nie musimy wywołać metodę unikalnego Child
w tej wersji kodu, ale możemy modyfikowanie lub przerobienie kodu później.
Zaletą silnego systemu typów jest to, że zapewnia nam pewne metadane dotyczące logiki naszego programu, dzięki czemu możliwości są bardziej widoczne. Jest to niezwykle przydatne w prototypowaniu, więc najlepiej zachować go tam, gdzie to możliwe.
Podsumowanie
Używanie Parent
bałaganu przy przeciążonej rozdzielczości metody, hamuje niektóre optymalizacje kompilatora, usuwa informacje z czytnika i sprawia, że kod jest brzydszy.
Używanie var
jest naprawdę właściwą drogą. Jest szybki, czysty, wzorowany i pomaga kompilatorowi i IDE poprawnie wykonywać swoje zadania.
Ważne : Ta odpowiedź dotyczyParent
porównaniaChild
w lokalnym zasięgu metody. KwestiaParent
vs.Child
jest bardzo różna dla typów zwracanych, argumentów i pól klas.