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

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


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

在此处运行代码

希望我很明白:)

评论


覆盖提供了多态性,阴影提供了该层次结构级别上的不同实现,但不是多态的。

–DavidRodríguez-dribeas
08年12月25日在11:10

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

–AnthonyWJones
08年12月25日在13:26

@AnthonyWJones,多态是一种(派生的)类型用作另一种(基本)类型的能力,其中实际实现(行为)是真正的特定(派生)类型。如果重写,则将通过引用base来调用派生方法,但是如果阴影不正确,则将调用派生方法。

–DavidRodríguez-dribeas
08年12月26日在9:11

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

–趋势
09年3月23日在15:38

否,因为bar是虚拟的,所以它仍将称为B Bar

–Stormenet
2010-2-6在8:21

#2 楼

阴影实际上是VB的用语,因为我们将其称为C#中的隐藏。

Stormenet通常在回答中显示出隐藏(在VB中为阴影)和覆盖。

A虚拟方法显示为被子类覆盖,并且即使在超类类型上或从超类的内部代码中对该方法的调用也将从子类中调用替换实现。

然后,当在子类上定义具有相同签名的方法时,将显示使用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变得具体,不能被覆盖。但是,也可以同时使用virtualnew关键字。

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的覆盖不会影响由于在B中使用了new,因此A上的虚拟方法隐藏了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类型规则的所有合法且可解释的规则从来都不是很直观的。

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

评论


很高兴知道。虽然使用它可能很危险:)

–Stormenet
08-12-25 at 13:17

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

–AnthonyWJones
08年12月25日在13:24

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

–乔克斯
08-12-29 at 15:49

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

–AnthonyWJones
08-12-29 at 16:41

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

– Sumit Kapadia
13年7月31日在17:58

#3 楼

我认为主要区别在于,使用阴影遮盖本质上是在重用名称,而忽略了超类的使用。通过覆盖,您可以更改实现,但不能更改可访问性和签名(例如,参数类型和返回值)。参见http://www.geekinterview.com/question_details/19331。

#4 楼

阴影是VB.NET概念。在C#中,阴影被称为隐藏。它隐藏了派生类方法。这是通过使用'new'关键字完成的。

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

评论


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

– Shaiju T
18年3月19日在13:14

#5 楼

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

Class A
{
}

Class B:A
{
}

A a = new B();


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

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

希望这会有所帮助...

Daniel Sandeep。

#6 楼

如果在某些情况下您无法更改类的内容,例如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();
    }
}