我对以下场景感到困惑,我们有一组这样的类
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
中的方法?
答案 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
)时,只有当你通过隐藏类型的实例访问它时才会调用它。当你使用基类的实例时,使用原始方法。
隐藏不是覆盖。