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

标签 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 的明显用例。

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

最佳答案

new modifier导致成员隐藏,这会破坏类层次结构中的多态关系。 BSayHi 方法被视为与 A不同(而不是覆盖)(因此选择"new"一词作为关键字)。 C 的方法然后覆盖 B 的方法,而不是 A 的方法(它仍然隐藏)。

因此,当您通过 A 引用在 C 实例上调用 SayHi 时,运行时将根据 A 解析它 类型,而不是 C 类型(其中 SayHi 是从 B 继承的"new"方法)。

另一方面,如果您要运行:

B p = new C();
p.SayHi();

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

From C

编辑:由于您请求了一个用例,这里有一个。在 .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 + "\""; }
    }
}

ObjectContainer 类的Item 属性返回一个普通的对象。但是,在 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类覆盖了StringContainerItem属性,继承了它的string返回类型;但是,它仍然object 隐藏 - 返回 ObjectContainerItem 属性。如果不是这样,就没有办法协调它们不同的返回类型……

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

关于c# - 这种继承特性的用例是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11039414/

相关文章:

c# - 在 C# 中,如何根据在 gridview 行中单击的按钮引用特定产品记录

c# - 在 DataReader 周围放置 "using"语句会关闭它吗?

javascript - 新/更新的元素继承旧元素 D3 的事件处理程序

c# - 如何在字节通过流时编辑字节?

ios - 如何从接口(interface)中的类继承?

c++ - 无法访问多态性子类的成员

asp.net-mvc-2 - nginx/mono 2.8 上的 ASP.Net MVC 2

c# - 我想在 Mono Windows 窗体中使用 WebBrowser 控件

.net - MailboxProcessor 在 Finalize 期间崩溃

c# - 以编程方式将调试器附加到在另一个应用程序域中运行的代码