У чому різниця між ключовими словами override
та і new
в C # при визначенні методів в ієрархіях класів?
Відповіді:
На наступній сторінці дуже красиво узагальнено ваше запитання.
Знання, коли використовувати заміщення та нові ключові слова
Резюме
Перевизначення : Коли метод базового класу замінений у похідному класі, використовується версія похідного класу, навіть якщо викличний код не "знає", що об'єкт є екземпляром похідного класу.
Нове : Якщо ви використовуєте нове ключове слово замість заміни, метод у похідному класі не замінює метод у базовому класі, він просто приховує його.
Якщо ви не вказали ні нових, ні перевизначень, отриманий результат буде таким же, як якщо б ви вказали новий, але ви також отримаєте попередження компілятора (оскільки ви можете не знати, що ви приховуєте метод у базовому класі метод, або ви, можливо, хотіли його замінити і просто забули включити ключове слово).
Замінити : використовується з типом методу віртуального / абстрактного / перевизначення в базовому класі
Нове : коли базовий клас не оголосив метод як віртуальний / абстрактний / замінює
new
буде затінювати метод абсолютно новим методом (який може мати або не мати той самий підпис) замість того, щоб замінити його (у цьому випадку новий метод повинен мати той самий підпис), що означає, що поліморфізм не буде працювати. Наприклад, у вас є такі класи:
class A {
public virtual int Hello() {
return 1;
}
}
class B : A {
new public int Hello(object newParam) {
return 2;
}
}
class C : A {
public override int Hello() {
return 3;
}
}
Якщо ви зробите це:
A objectA;
B objectB = new B();
C objectC = new C();
Console.WriteLine(objectB.Hello(null)); // 2
Console.WriteLine(objectC.Hello()); // 3
objectA = objectB;
Console.WriteLine(objectA.Hello()); // 1
objectA = objectC;
Console.WriteLine(objectA.Hello()); // 3
Оскільки ви можете визначити нові підписи методів new
за допомогою, компілятору неможливо знати, що екземпляр A
насправді є екземпляром, B
і новий метод, який B
визначає, повинен бути доступним. new
може використовуватися, коли метод, властивість, поле чи подія батьківського об'єкта не оголошені за допомогою virtual
, а через відсутність virtual
компілятора не буде "шукати" успадкований метод. З virtual
і override
, однак, це працює.
Я настійно рекомендую вам уникати new
; в кращому випадку це бентежить, оскільки ви визначаєте метод з іменем, яке можна розпізнати як щось інше, а в гіршому - він може приховувати помилки, вводити, здавалося б, неможливі помилки та ускладнювати розширення функціональності.
Hello()
, присвоює B змінній з типом інтерфейсу). Було б непогано пояснити це також у вашій відповіді, оскільки саме таку ситуацію я шукав.
Схоже на старе запитання, дозвольте спробувати іншу відповідь:
new
: як випливає з назви, це новий член у сімействі ієрархії успадкування, і він буде використовуватися як базовий член для подальшого руху по ланцюжку (якщо позначений як віртуальний).
override
: Це означає, що я не приймаю реалізацію члена мого батьківського класу, і я буду робити інакше.
Розглянемо таку ієрархію класів:
using System;
namespace ConsoleApp
{
public static class Program
{
public static void Main(string[] args)
{
Overrider overrider = new Overrider();
Base base1 = overrider;
overrider.Foo();
base1.Foo();
Hider hider = new Hider();
Base base2 = hider;
hider.Foo();
base2.Foo();
}
}
public class Base
{
public virtual void Foo()
{
Console.WriteLine("Base => Foo");
}
}
public class Overrider : Base
{
public override void Foo()
{
Console.WriteLine("Overrider => Foo");
}
}
public class Hider : Base
{
public new void Foo()
{
Console.WriteLine("Hider => Foo");
}
}
}
Вихідні дані вищезазначених кодів повинні бути:
Overrider => Foo
Overrider => Foo
Hider => Foo
Base => Foo
- Підклас
overrides
віртуального методу, застосовуючиoverride modifier
:- Якщо ви бажаєте
hide
учасника навмисно, у цьому випадку ви можете застосувати йогоnew modifier
до учасника в підкласі.The new modifier does nothing more than suppress the compiler warning that would otherwise result
Program
клас та інші класи на два окремі блоки коду, з результатом, вбудованим із викликом методу як коментар, наприклад base2.Foo(); // Base => Foo
. Я б також залишив простір імен та імпорту, але якщо ви хочете надати запущений код, тоді просто перейдіть за посиланням на dotnetfiddle.net
override
дозволяє вам перевизначити віртуальний метод у базовому класі, щоб ви могли помістити іншу реалізацію. new
приховає невіртуальний метод у базовому класі.
new
це абсолютно незалежний метод, який просто має однакову назву.