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

dot*_*hen 18 c# mono inheritance

继承继承的类时,new/override行为不是我所期望的:

$ 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
Run Code Online (Sandbox Code Playgroud)

由于C类覆盖了sayHi()方法,我希望输出为From C.为什么B类的new修饰符优先于此?那是什么用例?特别是因为它打破了C真正覆盖A的明显用例.

请注意,上面的代码是在Debian派生的发行版上运行的Mono 2.10上运行的.但我已经使用MS Visual Studio中的C#编译器确认了相同的行为.

Dou*_*las 21

new修改使成员隐藏,它打破在你的类层次结构中的多态性关系.该SayHi方法B被视为与s的不同(不是覆盖)A(因此选择单词"new"作为关键字).C的方法然后覆盖了B,而不是A(它仍然是隐藏的).

因此,当你调用SayHi一个C通过一个实例A参考,运行时会解决它针对A类型,而不是C类型(在其中SayHi是继承了"新"的方法B).

另一方面,如果你要跑:

B p = new C();
p.SayHi();
Run Code Online (Sandbox Code Playgroud)

...你会得到预期的多态结果:

From C
Run Code Online (Sandbox Code Playgroud)

编辑:由于您请求了一个用例,这里是一个.在.NET Framework 2.0中引入泛型之前,成员隐藏有时用作更改派生类中的继承方法的返回类型(在覆盖时无法执行的操作)以返回更多特定类型的方法.例如:

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 + "\""; }
    }
}
Run Code Online (Sandbox Code Playgroud)

该类的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
Run Code Online (Sandbox Code Playgroud)

QuotedStringContainer类覆盖了Item财产StringContainer,继承了它的string返回类型; 然而,它仍然隐藏在 - object令人遗憾的Item财产中ObjectContainer.如果不是这样,就没有办法调和他们不同的回报类型......

ObjectContainer oc = new QuotedStringContainer();
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 QuotedStringContainer.Item is now resolved
                       // (polymorphism!)
string s3 = ((QuotedStringContainer)oc).Item;   
                       // Valid, since QuotedStringContainer.Item is now resolved
Run Code Online (Sandbox Code Playgroud)


Ode*_*ded 7

C被重写阴影的方法的版本(其正被阴影B),而不是重写中之一A.

因此,当您使用类型的变量时A,将调用已SayHi定义的A内容,因为未被覆盖C.


ear*_*ess 6

C覆盖B的方法,所以当你把它投射到时A,你最终会调用定义的虚拟A.

请参阅ECMA 334: 17.5.3下的C#语言规范几乎就是您的示例(第294页).