В чем разница между затенением и переопределением метода в C #?
Ответы:
Ну наследство ...
предположим, у вас есть эти классы:
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, он будет возвращать значения, возвращаемые базовым классом, вместо того, чтобы следовать дереву наследования реального типа объекта.
Надеюсь, я понимаю :)
Затенение - это на самом деле язык 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, Fooреализация Thing () остается доступной и переопределяемой. Все законно и объяснимо в соответствии с правилами типа .NET, но при этом совершенно неинтуитивно.
Я опубликовал этот ответ, чтобы лучше понять, как все работает, а не как предложение методов, которые можно использовать свободно.
Я думаю, что основное отличие состоит в том, что при затенении вы по сути повторно используете имя и просто игнорируете использование суперкласса. При переопределении вы меняете реализацию, но не доступность и подпись (например, типы параметров и возврат). См. Http://www.geekinterview.com/question_details/19331 .
Затенение - это концепция VB.NET. В C # затенение называется скрытием. Он скрывает метод производного класса. Это достигается с помощью ключевого слова new.
Ключевое слово Override используется для предоставления полностью новой реализации метода базового класса (помеченного как «Виртуальный») в производном классе.
В основном, если у вас есть что-то вроде ниже,
Class A
{
}
Class B:A
{
}
A a = new B();
Любой метод, который вы вызываете для объекта 'a', будет выполнен с типом 'a' (здесь тип 'A'). Но если вы реализуете тот же метод в классе B, который уже присутствует в классе A, компилятор будет предупредить вас об использовании ключевого слова «Новое». Если вы используете «Новый», предупреждение исчезнет. Кроме этого, нет никакой разницы между использованием «New» или неиспользованием его в унаследованном классе.
В некоторых ситуациях вам может потребоваться вызвать метод ссылочного класса, который конкретный экземпляр содержит в данный момент, вместо вызова метода для типа объекта. В приведенном выше случае ссылка, которую он содержит, - «B», но тип - «A». Поэтому, если вы хотите, чтобы вызов метода происходил на «B», для этого используйте Virtual и override.
Надеюсь это поможет...
Дэниел Сандип.
Если есть случай, в котором вы не можете изменить содержимое класса, скажем A, но вы хотите использовать его некоторые методы, а также у вас есть метод с общим именем, вы можете использовать свою собственную реализацию метода по newключевому слову.
Суть заключается в том, чтобы использовать то, что и ссылка, и объект должны быть одного типа.
class A
{
public void Test()
{
Console.WriteLine("base");
}
}
class B : A
{
public new void Test()
{
Console.WriteLine("sub");
}
public static void Main(string[] args)
{
A a = new A();
B aa = new B();
a.Test();
aa.Test();
}
}