Разница между затенением и переопределением в С#?

Какая разница между затенением и переопределением метода в С#?

Ответ 1

Наследование наследования...

Предположим, что у вас есть эти классы:

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 cast B to an A class
Console.WriteLine(((A)clB).Foo()); // output 5 <<<-- shadow
Console.WriteLine(((A)clB).Bar()); // output 1

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

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

Надеюсь, у меня есть смысл:)

Ответ 2

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

Часто скрытие (затенение в 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, Foo реализация Thing() остается доступной и переопределяемой. Все юридические и объяснимые в соответствии с правилами типа .NET никогда не бывают совершенно неинтуитивными.

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

Ответ 3

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

Ответ 4

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

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

Ответ 5

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

Class A
{
}

Class B:A
{
}

A a = new B();

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

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

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

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