继承继承的类时,新的/覆盖行为不是我所期望的:
$ cat Program.cs
using System;
class A {
public virtual void SayHi() {
Console.WriteLine("From A");
}
}
class B : A {
public new virtual void SayHi() {
Console.WriteLine("From B");
}
}
class C : B {
public override void SayHi() {
Console.WriteLine("From C");
}
}
public class Program {
public static void Main() {
A p = new C();
p.SayHi();
}
}
$ ./Program.exe
From A
由于C类覆盖了sayHi()方法,我希望输出为From C
。为什么B类的new
修饰符优先于此?那是什么用例?特别是因为它打破了C真正覆盖A的明显用例。
请注意,上面的代码是在Debian派生的发行版上运行的Mono 2.10上运行的。但我在MS Visual Studio中使用C#编译器确认了相同的行为。
答案 0 :(得分:21)
new
modifier导致成员隐藏,这会破坏类层次结构中的多态关系。 SayHi
的{{1}}方法被B
视为 distinct (不是覆盖)(因此选择“new”作为关键字) 。 A
的方法然后覆盖C
,而不是B
(隐藏其中)。
因此,当您通过A
引用在SayHi
实例上调用C
时,运行时会根据A
类型解析它,而不是A
} type(其中C
是从SayHi
继承的“新”方法。)
另一方面,如果你要跑:
B
...你会得到预期的多态结果:
B p = new C();
p.SayHi();
编辑:由于您请求了一个用例,所以这是一个。在.NET Framework 2.0中引入泛型之前,成员隐藏有时用作更改派生类中的继承方法的返回类型(在覆盖时无法执行的操作)以返回更多特定类型的方法。例如:
From C
class ObjectContainer
{
private object item;
public object Item
{
get { return item; }
set { item = value; }
}
}
class StringContainer : ObjectContainer
{
public new virtual string Item
{
get { return base.Item as string; }
set { base.Item = value as string; }
}
}
class QuotedStringContainer : StringContainer
{
public override string Item
{
get { return "\"" + base.Item + "\""; }
}
}
类的Item
属性返回普通ObjectContainer
。但是,在object
中,隐藏此继承的属性以返回StringContainer
。因此:
string
ObjectContainer oc = new StringContainer();
object o = oc.Item; // Valid, since ObjectContainer.Item is resolved
string s1 = oc.Item; // Not valid, since ObjectContainer.Item is still resolved
string s2 = ((StringContainer)oc).Item;
// Valid, since StringContainer.Item is now resolved
类会覆盖QuotedStringContainer
的{{1}}属性,继承其Item
返回类型;但是,仍隐藏StringContainer
- string
object
属性Item
。如果不是这样的话,就没有办法调和他们不同的回报类型......
ObjectContainer
答案 1 :(得分:7)
答案 2 :(得分:6)
C
会覆盖B
的方法,因此当您将其投放到A
时,您最终会调用A
中定义的虚拟广告。
请参阅17.5.3下的ECMA 334: C# Language Specification几乎是您的示例(第294页)。
答案 3 :(得分:2)
因为C类没有覆盖A类中的SayHi方法,所以它覆盖了新的' B中的方法由于你的演员阵容是A,编译器将其解析为对A.SayHi()的调用而不是C.SayHi()
答案 4 :(得分:2)
这个msdn页面的最后一个example解释了这里发生的事情。
基本上,new修饰符会导致A中的方法从C中隐藏,并且因为它在C覆盖时是公共的,所以它会覆盖B中的方法(它被视为自己的不同方法)。
如果将B中的方法设置为private,则C将再次覆盖A中的方法。
class B : A
{
private new void SayHi()
{
Console.WriteLine("From B");
}
}
结果:From C