C#中的阴影和覆盖之间的区别?


100

阴影覆盖 C#中的方法有什么区别?

Answers:


152

好继承...

假设您有以下课程:

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

假设您有一个基类,并且在所有代码中都使用基类而不是继承的类,并且使用了影子,它将返回基类返回的值,而不是遵循对象实际类型的继承树。

在这里运行代码

希望我有道理:)


16
覆盖提供了多态性,阴影提供了该层次结构级别上的不同实现,但不是多态性。
大卫·罗德里格斯(DavidRodríguez)-德里贝斯

@dribeas,您将使用什么多态性定义得出结论?
AnthonyWJones

9
@AnthonyWJones,多态是一种(派生的)类型用作另一种(基本)类型的能力,其中实际实现(行为)是真正的特定(派生)类型。如果覆盖,派生方法将通过参考基地被调用,但如果你的影子,事实并非如此
大卫·罗德里格斯- dribeas

2
在我看来,您的示例代码中有错误。强制转换应该是((A)clB).Foo(),不是吗?
Trendl

1
不,因为酒吧是虚拟酒吧,所以它仍将称为B酒吧
Stormenet 2010年

32

阴影实际上是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"; }
}

对于的外部继承者BarFooThing()的实现仍然可以访问并且可以重写。依照.NET类型规则的所有合法且可解释的规则都非常不直观。

我发布此答案是为了加深对事物工作原理的理解,而不是作为可以自由使用的技术的建议。


2
很高兴知道。尽管使用起来可能很危险:)
Stormenet'

2
如果使用不当,所有工具都可能很危险。
AnthonyWJones

1
但是,它的可用性确实令人怀疑!是否有使用此的“严肃”开源应用程序?
乔克斯

4
可用性?你是说有用吗?直到您需要它们之前,边缘的东西似乎都没用。
AnthonyWJones

似乎只有在虚拟剧本和新剧本中,阴影才会出现。@Stormenet的解释仅覆盖内容,因为除非是虚拟的,否则调用其自己的方法是类的正常行为。
Sumit Kapadia


5

阴影是VB.NET概念。在C#中,阴影被称为隐藏。它隐藏了派生类方法。使用“ new”关键字即可完成。

Override关键字用于在派生类中提供基类方法(标记为“虚拟”)的全新实现。


你的意思是。它隐藏派生类方法,而使用基类方法。?
shaijut

0

基本上,如果您有类似以下内容,

Class A
{
}

Class B:A
{
}

A a = new B();

您在对象'a'上调用的任何方法都将使用'a'类型(这里的类型为'A'),但是如果您在类B中实现了与类A中已经存在的相同方法,则编译器将会警告您使用“新建”关键字。如果使用“新建”,警告将消失。除此之外,在继承的类中使用“新建”与不使用它之间没有区别。

在某些情况下,您可能需要调用当时特定实例拥有的引用类的方法,而不是针对对象类型调用方法。在上述情况下,它持有的引用为“ B”,但类型为“ A”。因此,如果您希望方法调用发生在“ B”上,则可以使用“虚拟”和“覆盖”来实现。

希望这可以帮助...

丹尼尔·桑迪普(Daniel Sandeep)。


0

假设存在无法更改类内容的情况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();
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.