Разница между затенением и переопределением в C #? - PullRequest
89 голосов
/ 25 декабря 2008

В чем разница между затенением и переопределением метода в C #?

Ответы [ 5 ]

139 голосов
/ 25 декабря 2008

Ну наследство ...

предположим, у вас есть следующие классы:

class A {
   public int Foo(){ return 5;}
   public virtual int Bar(){return 5;}
}
class B : A{
   public new int Foo() { return 1;}     //shadow
   public override int Bar() {return 1;} //override
}

тогда, когда вы звоните это:

A clA = new A();
B clB = new B();

Console.WriteLine(clA.Foo()); // output 5
Console.WriteLine(clA.Bar()); // output 5
Console.WriteLine(clB.Foo()); // output 1
Console.WriteLine(clB.Bar()); // output 1

//now let's cast B to an A class
Console.WriteLine(((A)clB).Foo()); // output 5 <<<-- shadow
Console.WriteLine(((A)clB).Bar()); // output 1

Предположим, что у вас есть базовый класс, и вы используете базовый класс во всем своем коде вместо унаследованных классов, и вы используете shadow, он будет возвращать значения, возвращаемые базовым классом, вместо следования дереву наследования реального типа объект.

Выполните код здесь

Надеюсь, я понимаю:)

31 голосов
/ 25 декабря 2008

Затенение на самом деле является языком VB для того, что мы называем сокрытием в C #.

Часто сокрытие (затенение в VB) и переопределение отображаются как в ответе Stormenet .

Показано, что виртуальный метод переопределяется подклассом, и вызовы этого метода даже для типа суперкласса или из внутреннего кода суперкласса вызовут реализацию замены из подкласса.

Затем показывается конкретный метод (не помеченный как виртуальный или абстрактный), который скрывается с помощью ключевого слова new при определении метода с идентичной подписью в подклассе. В этом случае, когда метод вызывается для типа суперкласса, используется оригинальная реализация, новая реализация доступна только для подкласса.

Однако часто упускается возможность скрыть виртуальный метод.

class A
{
    public virtual void DoStuff() { // original implementation }
}

class B : A
{
    public new void DoStuff() {  //new implementation }
}

B b = new B();
A a = b;

b.DoStuff(); //calls new implementation
a.DoStuff(); //calls original implementation.

Обратите внимание, что в приведенном выше примере DoStuff становится конкретным и не может быть переопределен. Однако можно также использовать оба ключевых слова virtual и new.

class A
{
    public virtual void DoStuff() { // original implementation }
}

class B : A
{
    public new virtual void DoStuff() {  //new implementation }
}

class C : B
{
    public override void DoStuff() { //replacement implementation }
}

C c = new C();
B b = c;
A a = b;

c.DoStuff(); //calls replacement implementation
b.DoStuff(); //calls replacement implementation
a.DoStuff(); //calls original implementation.

Обратите внимание, что, несмотря на то, что все используемые методы являются виртуальными, переопределение на C не влияет на виртуальный метод на A, поскольку использование new в B скрывает реализацию A.

Редактировать: В комментариях к этому ответу было отмечено, что вышеупомянутое может быть опасным или, по крайней мере, не особенно полезным. Я бы сказал, да, это может быть опасно и было бы там, если бы это было вообще полезно.

В частности, вы можете столкнуться со всевозможными проблемами, если вы также измените модификаторы доступности. Например: -

public class Foo
{
    internal Foo() { }
    protected virtual string Thing() { return "foo"; }
}

public class Bar : Foo
{
 internal new string Thing() { return "bar"; }
}

Для внешнего наследника Bar реализация Thing () в Foo остается доступной и переопределяемой. Все законно и объяснимо в соответствии с правилами типа .NET, тем не менее, совершенно неинтуитивно.

Я опубликовал этот ответ, чтобы углубить понимание того, как все работает, а не как предложение техник, которые можно свободно использовать.

6 голосов
/ 25 декабря 2008

Я думаю, что главное отличие состоит в том, что при теневом копировании вы по существу повторно используете имя и просто игнорируете использование суперкласса. При переопределении вы меняете реализацию, но не доступность и сигнатуру (например, типы параметров и возвращаемый результат). См http://www.geekinterview.com/question_details/19331.

4 голосов
/ 02 марта 2014

Shadowing - это концепция VB.NET. В C # Shadowing известен как Hiding. Он скрывает метод производного класса. Это достигается с помощью ключевого слова "new".

Ключевое слово Override используется для обеспечения полностью новой реализации метода базового класса (который помечен как «Виртуальный») в производном классе.

0 голосов
/ 06 октября 2011

В основном, если у вас есть что-то вроде ниже,

Class A
{
}

Class B:A
{
}

A a = new B();

Любой метод, который вы вызываете для объекта «а», будет выполнен с типом «а» (здесь тип «А») Но если вы реализуете тот же метод в классе B, который уже присутствует в классе A, компилятор выдаст вам предупреждение для использования ключевого слова «New». Если вы используете «Новый», предупреждение исчезнет. Кроме этого, нет никакой разницы между использованием «New» или неиспользованием его в унаследованном классе.

В некоторых ситуациях вам может потребоваться вызвать метод ссылочного класса, который в данный момент хранится в конкретном экземпляре, вместо вызова метода типа объекта. В вышеприведенном случае ссылка, которую он содержит, это «B», но тип «A». Поэтому, если вы хотите, чтобы вызов метода происходил в «B», вы используете Virtual и override для достижения этого.

Надеюсь, это поможет ...

Даниэль Сандип.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...