Method overriding和方法隐藏的执行流程

时间:2012-08-27 10:40:50

标签: c# overloading method-hiding

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

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
}

我得到了像这样的输出

  

B B D D

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

3 个答案:

答案 0 :(得分:4)

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

这解释了常见的情况,如

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

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

那么A a = new D(); a.SomeMethod();做了什么?该变量声明为A,因此必须在A上定义针对它调用的所有方法/属性/等。 C定义了方法SomeMethod(并D覆盖了它),但此方法在A上不存在,因此不能在这里调用。 SomeMethod的最派生实现(在A类型上声明)位于B中,因此这是调用的实现。

B b = new D(); b.SomeMethod();

的相同故事

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

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

其他人发布了良好的链接。这是另一个可能有用的线程:C# and method hiding

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

答案 1 :(得分:3)

我尝试以不同的方式解释它。

virtual / override表示您实现/更改同一方法的行为。它是polymorphism的实现。使用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)。

答案 2 :(得分:2)

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

隐藏不是覆盖