这种继承特性的用例是什么?

时间:2012-06-14 18:43:56

标签: c# inheritance mono

继承继承的类时,新的/覆盖行为不是我所期望的:

$ 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#编译器确认了相同的行为。

5 个答案:

答案 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)

C会覆盖方法的shadowed版本(B中的shadowed),而不是覆盖A中的{。}}。

结果,当您使用A类型的变量时,SayHi中定义的A被调用,因为未被覆盖C

答案 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