В чем разница override и new для методов в C#
Что проверяют
Понимаете ли вы, как C# выбирает метод при вызове: по реальному типу объекта или по типу переменной. Следом почти всегда дают код с Base b = new Derived(); b.Show(); и просят сказать, что напечатается в каждом варианте.
Как отвечать
Суть различия в том, где решается, какой метод вызвать:
override: переопределяет метод, помеченный в базовом классе какvirtual,abstractили ужеoverride. Вызов идёт через таблицу виртуальных методов, поэтому по ссылке типаBaseвыполнится версияDerived. Это и есть полиморфизм;new: объявляет в наследнике новый метод с тем же именем, который просто скрывает базовый. Связи между ними нет, выбор делается на этапе компиляции по статическому типу переменной. ЧерезBase bвызовется базовая версия, черезDerived dновая;- без ключевого слова: если объявить в наследнике метод с той же сигнатурой и ничего не указать, компилятор выдаст предупреждение CS0108 и поведёт себя как с
new. Словоnewздесь только говорит «я скрываю намеренно».
Полезно добавить детали. override не может менять сигнатуру и модификатор доступа, а sealed override запрещает переопределять метод дальше по иерархии. Вызвать базовую реализацию изнутри можно через base.Show(). Скрытие через new работает и для невиртуальных методов, свойств и полей, а override только для виртуальных членов.
Когда new вообще оправдан: в базовом классе из чужой библиотеки в новой версии появился метод с тем же именем, что уже был у вас, и переписать свой код прямо сейчас нельзя. В обычном проектировании скрытие чаще признак ошибки, чем приём.
Где спотыкаются
Говорят, что new тоже «переопределяет метод». Нет: при обращении через базовый тип new-версия невидима, и это главный источник багов, когда объекты хранятся в List<Base>.
Путают, где принимается решение. У override метод выбирается в рантайме по фактическому типу, у new компилятором по объявленному типу переменной.
Игнорируют предупреждение CS0108 и получают скрытие случайно, хотя хотели переопределения, просто забыли virtual в базовом классе.