Резюме для программиста
По-моему, эти названия - new и override - ничего не говорят и выбраны неудачно. Я сколько ни читал описания в МСДН, что этот скрывает, а этот переписывает - так и не понял логики, почему один так называется, а другой так. Они оба скрывают и переписывают, только один в одном случае, а другой в другом. Если кто попытается понять, почему в этом случае вы назвали это сокрытием, а в другом - переписыванием, тот голову сломает и ничего не запомнит. На следующем собесе с каверзными вопросами вы этот вопрос завалите, если вы до этого постоянно эти конструкции не используете с присвоением производных классов базовым и проверке - а что там выводить будет.
По мне, так override скрывает метод базового класса, а new - переписывает. Это понятия, настолько зависящие от контекста, ну типа как разглядывание цифры "6" с противоположных сторон, что если заменить их на "шняжка" и "фигняшка", то в понимании ничего не ухудшится.
Потому что логические действия программы пытаются описать семантическими понятиями ключевых слов, взятых из естественного языка, который нифига не логичен.
По-моему, эти названия - new и override - ничего не говорят и выбраны неудачно.
Все станет понятно как только ты BaseClass определишь так:
class BaseClass { public virtual void Method1() { Console.WriteLine("Base - Method1"); } public /* virtual */ void Method2() { Console.WriteLine("Base - Method2"); } }
А вообще за подобные конствукции надо руки вырывать :)
Как вы считаете, лучше по автобану ехать, или по бунде, если время примерно одинаковое, но по автобану немного больше расстояние (до него ещё доехать надо)?
Откуда и куда ты ездить собираешься?
Откуда и куда ты ездить собираешься?
На работу и обратно. У меня в городе нормальной работы программистом нет.
А вообще за подобные конствукции надо руки вырывать :)
Это всего лишь упрощённые задачки при приёме на работу джуниора. Вот ещё проще. Я тут даже типы не приводил. В реальном коде обычно запутаннее.
Что будет выведено? Без запуска и без подглядывания.
class Program { static void Main(string[] args) { new A().Method1(); new B().Method1(); new C().Method1(); new D().Method1(); A a = new B(); a.Method1(); a.Method2(); A aa = new C(); aa.Method1(); aa.Method2(); A aaa = new D(); aaa.Method1(); aaa.Method2(); B b = new D(); b.Method1(); b.Method2(); } } class A { public void Method1() { Console.WriteLine("A1"); Method2(); } public virtual void Method2() { Console.WriteLine("A2"); } } class B : A { public override void Method2() { Console.WriteLine("B2"); } } class C : A { public new void Method2() { Console.WriteLine("C2"); } } class D : B { public new void Method2() { Console.WriteLine("D2"); } }
Можно немного усложить задачу, если вызывать, например, в методе 2 производного класса метод 1. Можно ещё и метод 1 переопределить, и вызывать их один из другого и 1 из 2 (или наборот). А можно ещё добавить приведение типов перед вызовом. Джуниор должен в уме решать такие задачки. В Новосибирске при устройстве в одну крупную фирму, имеющую филиалы за рубежом, кстати - только так.
Как человек может вообще быть допущен к написанию кода, если не знает таких элементарных вещей? Это как дышать и не понимать, как дышишь - как воздух в лёгкие поступает, как кислород в кровь проходит, окислительно-восстановительные процессы. Стоит только на секунду забыть об этом, как сразу начнёшь задыхаться.
В реальности же всё гораздо сложнее - на все эти наследования ещё и многопоточность накладывается, и лямбды с захватом переменных, и асинхронный вызов делегатов, и ковариация с контравариацией, и unsafe с вызовами сторонних библиотек на других языках, и обработка исключений - всё вместе и одновременно, и быстро починить упавший вдруг сервак, и чтобы ещё вчера. А если баг в инструментарии? А если на ОС пришло обновление с ошибками? И что, что не в тебе дело? А виноват-то ты! Тебе за результат платят, а не за жалобы! А за порогом же толпа стоит - любой тебя готов заменить в любую секунду за меньшую зарплату. Они все ждут, когда ты споткнёшься и допустишь ошибку, не исправишь баг, или откажешься оставаться сверурочно... Я думаю, Шумахер в своём болиде даже под конец гонки чувствует себя куда комфортнее, чем программист за чашечкой кофе в самом начале рабочего дня.
По-моему, эти названия - new и override - ничего не говорят и выбраны неудачно. Я сколько ни читал описания в МСДН, что этот скрывает, а этот переписывает - так и не понял логики, почему один так называется, а другой так. Они оба скрывают и переписывают, только один в одном случае, а другой в другом. Если кто попытается понять, почему в этом случае вы назвали это сокрытием, а в другом - переписыванием, тот голову сломает и ничего не запомнит. На следующем собесе с каверзными вопросами вы этот вопрос завалите, если вы до этого постоянно эти конструкции не используете с присвоением производных классов базовым и проверке - а что там выводить будет.
По мне, так override скрывает метод базового класса, а new - переписывает. Это понятия, настолько зависящие от контекста, ну типа как разглядывание цифры "6" с противоположных сторон, что если заменить их на "шняжка" и "фигняшка", то в понимании ничего не ухудшится.
Потому что логические действия программы пытаются описать семантическими понятиями ключевых слов, взятых из естественного языка, который нифига не логичен.
Даже в МСДН либо почти нигде не объяснено, что означает "скрывает" и "переписывает", либо это разбросано в разных местах в разных примерах кода, так что в голове единая картина не складывается.
Почему, например, override переписывает, а new - скрывает? Взять из моего примера кода
new B().Method1();
Тут внутри метода 1 в базовом классе А вызывается метод 2 производного класса В, а не базового же класса А. Т.е. получается, что override скрыл метод 2 базового класса А? А почему "скрыл" используется для new?
А всё потому, что эта терминология используется для производного класса относительно базового. В производном классе override перезаписывает методы базового класса, а new - скрывает их. Если же мы находимся в базовом классе, то тут лучше использовать другие слова: при вызове базового члена из производного, override заставляет использовать производный член, а new - позволяет использовать базовый. Причём понятия "мы находимся в базовом" или "мы находимся в производном" классах - верны в любом случае. Т.е. что мы находимся в методе какого-то класса, что мы приводим тип.
Например, в случае
new B().Method1();
мы находимся в производном классе, вызываем метод базового, и внутри базового мызываем метод, который есть в обоих классах иерархии наследования, но в производном определён как override. Это заставляет использовать вместо базового метода производный. Т.е. override скрывает метод базового класса.
В случае
new C().Method1();
мы находимся в производном, вызываем метод базового, внутри него - метод, который есть в обоих классах в иерархии, но в производном определён как new. Это позволяет нам использовать в базовом классе базовую версию метода. Здесь new ничего не скрывает, а наоборот, позволяет использовать. Понятие скрывает к этому случаю неприменимо. Сокрытие new базовых членов применимо, когда мы находимся в производном классе и хотим вызвать член, которые есть в обоих классах в иерархии. В объяснениях же в МСДН и прочих переводных, которые обычно переводятся тупо и без осмысления, написана какая-то хрень и абракадабра, которую невозможно понять, т.к. всё описано несоответственно семантике употребляемых терминов, или не уточняется, в каком контексте мы находимся - в контексте базового класса, производного или это случай приведения типов, или случай вызова производного метода из базового метода из производного класса.
Впрочем, мои "позволяет" и "заставляет" тоже нужно убрать.
Итого, как я считаю, правильное понимание ключевых слов new и override:
new:
- при вызове базовых членов из производных вызываются базовые члены;
- при вызове производных из производных вызываются производные члены, если их поведение не переопределено в более производных;
override
- при вызове базовых членов из производных вызываются производные члены;
- при вызове производных из производных вызываются производные члены, если их поведение не переопределено в более производных;
Итого получается, что если в производных классах ничего не переопределено или этих классов вообще нет, то их члены вызываются, как если бы у этих классов не было предков - т.е. нельзя вызвать базовые версии членов. (На самом деле можно, но лучше так не делать.)
Это всего лишь упрощённые задачки при приёме на работу джуниора.
Я бы сказал, что это нарушение принципа Барбары Лисков (L из SOLID).
Люди годами делают сотни миллионов денег, принимая на работу по таким задачкам, люкам и шарикам в автобусах, а вы им солидами всякими тыкать будете? Солиды и прочие лисковы - для лохов, которые не могут залить баблом свою дурь. )))
Да ладно, просто напишите результат вывода хотя бы по этому, без подгляда и запуска:
A aaa = new D();
aaa.Method1();
aaa.Method2();
B b = new D();
b.Method1();
b.Method2();
Я вот, следуя своей логике, что выше написал, всё правильно решил. А читая МСДНы и прочие описания - нихрена понять не мог, почему у меня не так, как в реальности выводится.
Правда, боюсь, что толку от этого не много, т.к. скоро забуду. А потом полезу опять читать в какой-нибудь МСДН, и снова будет каша в голове с их пояснений. Наверняка все эти условия с new и override внутри Дотнета какой-нибудь пачкой if'ов описываются при разборе иерархии наследования, какую версию какого метода вызвать. А они, вместо того, чтобы просто логическую таблицу с этими if'ами привести, начинают дуть в уши про "тут скрываем, тут перезаписываем", безотносительно того, где и что имеется ввиду.
Вот если устроюсь на работу и доберусь до собесов, ух я тогда отыграюсь на всех! Тоже буду каверзные задачки спрашивать. Ещё и покруче чего придумаю! А начальству буду говорить, что вокруг одни дураки, не знают базовых основ. ))) Нас чморили, теперь мы будем чморить. Дедовщина, короче. )))
Я бы сказал, что это нарушение принципа Барбары Лисков (L из SOLID).
Почему? Не вижу. То что B и D перестают из Method1 вызывать Method2 это не нарушение. Изменили поведение - да, но никакой инвариант не сломали.
Почему? Не вижу. То что B и D перестают из Method1 вызывать Method2 это не нарушение. Изменили поведение - да, но никакой инвариант не сломали.
Потому что принцип фактически сводится к "наследуемый класс должен дополнять, а не замещать поведение базового объекта".
т.е. если ты сделаешь тест для класса А и этот тест выдал зелененький результат, то тест с объектом класса Б (Б унаследован от А) тоже должен давать зеленый результат.
При этом в случае с new есть еще одна засада - программист, который использует Б должен знать делали реализации.
Так что в этом примере плохо абсолютно все.
Ну, тут не в примере дело. new отвратителен сам по себе. Но уж такая у сионистов карма, без корявостей никуда :)
А поведение... Так нет у этих классов никакого поведения. Их методы состояние не изменяют и никакой контракт нигде не задекларирован. Так что и менять нечего. А вывод на консоль это не поведение, это "побочный эффект".
Итого, как я считаю, правильное понимание ключевых слов new и override
для себя можно делать всё что угодно.
А вот то что это будет понятно и другим еще вопрос.
На работу и обратно. У меня в городе нормальной работы программистом нет.
Я так то спросила пункт А-Пункт Б. Иначе твой вопрос про дорогу на работу не имеет смысла.
Или вы имеете ввиду пристроить на любую работу вообще, хоть мусор убирать на улицах?
нет, на работу по специальности.
Сейчас берут всех. Хз что у тебя за проблемы.
дипломом - это другая статья, не положено. В АА "академикер"
спорить не буду, но разве оно так работает?
Так ведь можно выучиться на инженера по добыче нефти и газа и посылать АА до пенсии на три буквы.
н.п.
Нормальные люди такие вопросы на собеседованиях не задают.
а если и задают, то есть риск, что у них так писать считается нормой.
но разве оно так работает?
Как работает во всех возможных случаях не знаю, не сталкивался. Хотя согласно законов (§ 10 SGB II und § 140 SGB III) подобных ограничений действительно нет.
Речь шла прежде всего о "стандартных примерах".