Какая разница между затенением и переопределением метода в С#?
Разница между затенением и переопределением в С#?
Ответ 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 и переопределяете его для достижения.
Надеюсь, что это поможет...
Даниэль Сандип.