4

我对以下场景感到困惑,我们有一组这样的类

public class A
{
    public virtual string SomeMethod()
    {
        return "A";
    }
}

public class B : A
{
    public override string SomeMethod()
    {
        return "B";
    }
}

public class C : B
{
    public new virtual string SomeMethod()
    {
        return "C";
    }
}

public class D : C
{
    public override string SomeMethod()
    {
        return "D";
    }
}

当我调用以下方法时

private void Test()
{
    A a = new D();
    B b = new D();
    C c = new D();
    D d = new D();
    Console.WriteLine(a.SomeMethod()); //The method in class B is being called
    Console.WriteLine(b.SomeMethod()); //The method in class B is being called
    Console.WriteLine(c.SomeMethod()); //The method in class D is being called
    Console.WriteLine(d.SomeMethod()); //The method in class D is being called
}

我得到这样的输出

BBDD

为什么调用的是继承的方法,而不是声明类型中的方法,为什么不是D每次都调用类中的方法?

4

3 回答 3

4

当您调用(ie )SomeMethod的实例时,您期望获得可用的最衍生版本。这就是继承的全部意义。您的代码只需要处理基类的实例,但如果这些实例恰好是派生类,则会调用特殊的派生实现。这是您在覆盖方法时得到的行为。AA foo = new <A or derived>()SomeMethod

这解释了常见的场景,如

A b = new B();
b.SomeMethod();  // B's implementation invoked

使用new,您并没有覆盖该方法,而是声明了一个具有相同名称的全新方法。 此方法仅存在于声明它的类及其子类中,它不是基类及其继承链的一部分。

那么做A a = new D(); a.SomeMethod();什么呢?该变量被声明为A,因此对其调用的任何方法/属性/等都必须在 上定义AC定义了一个方法SomeMethod(并D覆盖它),但是这个方法在 上不存在A,所以不能在这里调用。SomeMethod(在 type 上声明的)最派生的实现A是 in B,所以这是被调用的实现。

同样的故事B b = new D(); b.SomeMethod();

只有当我们到达时C c = new D(); c.SomeMethod()方法才有机会执行。这是因为变量是 a C,因此方法SomeMethod是第一次在变量类型上声明。并且如上所述,将调用最可能派生的版本,在这种情况下,这意味着版本被D.

我希望我们都在同一个页面上D d = new D(); d.SomeMethod():)

其他人发布了很好的链接。这是另一个可能有帮助的线程:C# and method hide

这里的最后一个示例显示了一个更奇怪的场景,其中“新”方法被声明为私有,因此进一步派生的类型实际上继承了该方法的基本版本,而不是继承“新”版本。http://msdn.microsoft.com/en-us/library/aa691135

于 2012-08-30T06:41:13.673 回答
3

我试图用不同的方式来解释它。

virtual/override表示您实现/更改同一方法的行为。它是多态性的一种实现。使用new,您可以创建一个全新的方法。它恰好与另一种方法具有相同的签名,但与它没有任何关系。

调用此方法时,取决于引用的类型(编译时类型),来选择您实际调用的方法。

您的代码相当于:

public class A
{
    public virtual string SomeMethod()
    {
        return "A";
    }
}

public class B : A
{
    public override string SomeMethod()
    {
        return "B";
    }
}

public class C : B
{
    public virtual string AnotherMethod()
    {
        return "C";
    }
}

public class D : C
{
    public override string AnotherMethod()
    {
        return "D";
    }
}

private void Test()
{
    A a = new D();
    B b = new D();
    C c = new D();
    D d = new D();
    Console.WriteLine(a.SomeMethod()); //The method in class B is being called
    Console.WriteLine(b.SomeMethod()); //The method in class B is being called
    Console.WriteLine(c.AnotherMethod()); //The method in class D is being called
    Console.WriteLine(d.AnotherMethod()); //The method in class D is being called
}

编译器选择调用 AnotherMethod 来引用类型 C(和 D)。

于 2012-08-30T05:20:06.083 回答
2

这是一个众所周知的行为:当您隐藏方法(使用new)时,仅当您通过隐藏类型的实例访问它时才会调用它;当您使用基类的实例时,将使用原始方法。

隐藏不是压倒一切的。

于 2012-08-27T10:46:49.220 回答