У чому різниця між заміною та новими ключовими словами в C #?


75

У чому різниця між ключовими словами overrideта і newв C # при визначенні методів в ієрархіях класів?

Відповіді:


101

На наступній сторінці дуже красиво узагальнено ваше запитання.

Знання, коли використовувати заміщення та нові ключові слова

Резюме

Перевизначення : Коли метод базового класу замінений у похідному класі, використовується версія похідного класу, навіть якщо викличний код не "знає", що об'єкт є екземпляром похідного класу.

Нове : Якщо ви використовуєте нове ключове слово замість заміни, метод у похідному класі не замінює метод у базовому класі, він просто приховує його.

Якщо ви не вказали ні нових, ні перевизначень, отриманий результат буде таким же, як якщо б ви вказали новий, але ви також отримаєте попередження компілятора (оскільки ви можете не знати, що ви приховуєте метод у базовому класі метод, або ви, можливо, хотіли його замінити і просто забули включити ключове слово).

Замінити : використовується з типом методу віртуального / абстрактного / перевизначення в базовому класі

Нове : коли базовий клас не оголосив метод як віртуальний / абстрактний / замінює


9
Ви можете також включити сюди важливу інформацію, будь ласка. Це допомагає зберігати інформацію тут і захищає від гниття посилань (навряд чи це стосується блогу MSDN, але ви ніколи не знаєте).
ChrisF

3
lol "малоймовірно" Я отримую переспрямування з наступним написом "Доступ заборонено У вас немає дозволу переглядати / завантажувати цей елемент."
tobsen

78

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; в кращому випадку це бентежить, оскільки ви визначаєте метод з іменем, яке можна розпізнати як щось інше, а в гіршому - він може приховувати помилки, вводити, здавалося б, неможливі помилки та ускладнювати розширення функціональності.


14
Це має бути прийнятою відповіддю. Це насправді на прикладах пояснює, які відмінності та наслідки. Прийнята відповідь досить розмита.
themetiman

щось подібне трапляється при використанні інтерфейсу (як у B розширює A, A реалізує інтерфейс з Hello(), присвоює B змінній з типом інтерфейсу). Було б непогано пояснити це також у вашій відповіді, оскільки саме таку ситуацію я шукав.
ahong

9

Схоже на старе запитання, дозвольте спробувати іншу відповідь:

  1. new : як випливає з назви, це новий член у сімействі ієрархії успадкування, і він буде використовуватися як базовий член для подальшого руху по ланцюжку (якщо позначений як віртуальний).

  2. override : Це означає, що я не приймаю реалізацію члена мого батьківського класу, і я буду робити інакше.


3

Розглянемо таку ієрархію класів:

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
ahong

1

overrideдозволяє вам перевизначити віртуальний метод у базовому класі, щоб ви могли помістити іншу реалізацію. newприховає невіртуальний метод у базовому класі.


стільки, що я знав, однак перевизначення фактично приховає метод базових класів
jaywayco

2
Жодне перевизначення не приховує метод базового класу. Заміщення робить виклики методу базового класу у виклики методу похідного класу. Певним чином із заміною метод у похідному класі є тим самим методом, що і метод у базовому класі. Тоді як newце абсолютно незалежний метод, який просто має однакову назву.
CodesInChaos

@CodeInChaos Дякую, що сказав те, що я хотів сказати краще, ніж зміг сказати :)
Даніель Манн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.