tl; dr - использованиеChild
overParent
предпочтительно в локальной области. Это не только помогает с удобочитаемостью, но также необходимо гарантировать, что разрешение перегруженного метода работает правильно и помогает включить эффективную компиляцию.
В местном масштабе
Parent obj = new Child(); // Works
Child obj = new Child(); // Better
var obj = new Child(); // Best
Концептуально, речь идет о поддержании максимально возможной информации. Если мы опустимся до Parent
, мы, по сути, просто удаляем информацию о типах, которая могла бы быть полезной.
Сохранение полной информации о типе имеет четыре основных преимущества:
- Предоставляет больше информации компилятору.
- Предоставляет больше информации для читателя.
- Более чистый, более стандартизированный код.
- Делает логику программы более изменчивой.
Преимущество 1: дополнительная информация для компилятора
Видимый тип используется в разрешении перегруженного метода и в оптимизации.
Пример: разрешение перегруженного метода
main()
{
Parent parent = new Child();
foo(parent);
Child child = new Child();
foo(child);
}
foo(Parent arg) { /* ... */ } // More general
foo(Child arg) { /* ... */ } // Case-specific optimizations
В приведенном выше примере оба foo()
вызова работают , но в одном случае мы получаем лучшее разрешение перегруженного метода.
Пример: оптимизация компилятора
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; }
}
В приведенном выше примере оба .Foo()
вызова в конечном итоге вызывают один и тот же override
метод, который возвращает 2
. Просто, в первом случае, есть поиск виртуального метода, чтобы найти правильный метод; этот поиск виртуального метода не требуется во втором случае, так как этот метод sealed
.
Благодарим @Ben, который привел аналогичный пример в своем ответе .
Преимущество 2: больше информации для читателя
Знание точного типа, т. Е. Child
Предоставляет больше информации тому, кто читает код, облегчая понимание того, что делает программа.
Конечно, может быть , это не имеет значения для фактического кода , поскольку оба parent.Foo();
и child.Foo();
имеют смысл, но для кого - то , видя код в первый раз, больше информации это просто полезна.
Кроме того, в зависимости от среды разработки, среда может быть в состоянии обеспечить более полезные подсказки и метаданные о Child
чем Parent
.
Преимущество 3: более чистый, более стандартизированный код
Большинство примеров кода на C #, которые я видел в последнее время, используют var
, что в основном является сокращением 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
Видя, что var
заявление не объявлено, просто выглядит отвратительно; если есть ситуативная причина для этого, круто, но в остальном это выглядит анти-паттерном.
// 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();
Преимущество 4: более изменчивая логика программы для прототипирования
Первые три преимущества были большими; этот гораздо более ситуативный.
Тем не менее, для людей, которые используют код, как другие используют Excel, мы постоянно меняем наш код. Может быть , нам не нужно вызывать метод , уникальный для Child
в этой версии кода, но мы могли бы перепрофилировать или переработать код позже.
Преимущество сильной системы типов состоит в том, что она предоставляет нам определенные метаданные о логике нашей программы, делая возможности более очевидными. Это невероятно полезно при создании прототипов, поэтому лучше хранить его там, где это возможно.
Резюме
Использование Parent
нарушает разрешение перегруженного метода, запрещает некоторые оптимизации компилятора, удаляет информацию из читателя и делает код более уродливым.
Использование var
действительно путь. Это быстро, чисто, по шаблону и помогает компилятору и IDE правильно выполнять свою работу.
Важный : этот ответ оParent
противChild
в локальной области метода. ПроблемаParent
vs.Child
очень отличается для возвращаемых типов, аргументов и полей класса.