Answers:
好继承...
假设您有以下课程:
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
假设您有一个基类,并且在所有代码中都使用基类而不是继承的类,并且使用了影子,它将返回基类返回的值,而不是遵循对象实际类型的继承树。
希望我有道理:)
阴影实际上是VB的说法,因为我们将其称为C#中的隐藏。
Stormenet经常显示隐藏(覆盖VB中的阴影)和重写。
虚拟方法显示为被子类覆盖,并且即使在超类类型上或从超类的内部代码中对该方法的调用也将从子类调用替换实现。
然后显示了一种具体的方法(未标记为虚拟或抽象的)通过使用 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。
基本上,如果您有类似以下内容,
Class A
{
}
Class B:A
{
}
A a = new B();
您在对象'a'上调用的任何方法都将使用'a'类型(这里的类型为'A'),但是如果您在类B中实现了与类A中已经存在的相同方法,则编译器将会警告您使用“新建”关键字。如果使用“新建”,警告将消失。除此之外,在继承的类中使用“新建”与不使用它之间没有区别。
在某些情况下,您可能需要调用当时特定实例拥有的引用类的方法,而不是针对对象类型调用方法。在上述情况下,它持有的引用为“ B”,但类型为“ A”。因此,如果您希望方法调用发生在“ B”上,则可以使用“虚拟”和“覆盖”来实现。
希望这可以帮助...
丹尼尔·桑迪普(Daniel Sandeep)。
假设存在无法更改类内容的情况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();
}
}