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

时间:2008-12-25 10:45:53

标签: c#

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

6 个答案:

答案 0 :(得分:139)

继承良好......

假设你有这个类:

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,它将返回基类返回的值,而不是遵循真实类型的继承树。对象。

Run code here

希望我有意义:))

答案 1 :(得分:31)

阴影实际上就是我们所说的隐藏在C#中的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变得具体,无法覆盖。但是,也可以同时使用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上的覆盖不会影响A上的虚方法,因为在B中使用new会隐藏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类型规则,所有合法且可解释的内容都是毫不含糊的。

我已经发布了这个答案,以加深对事情如何运作的理解,而不是作为可以自由使用的技术的建议。

答案 2 :(得分:6)

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

答案 3 :(得分:4)

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

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

答案 4 :(得分:0)

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

Class A
{
}

Class B:A
{
}

A a = new B();

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

在某些情况下,您可能需要调用特定实例在该时刻保存的引用类的方法,而不是调用对象类型上的方法。在上面的例子中,它所持有的引用是'B',但类型是'A'。因此,如果您希望方法调用应该在'B'上进行,那么您可以使用Virtual和override来实现此目的。

希望这会有所帮助......

Daniel Sandeep。

答案 5 :(得分: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();
    }
}