【问题标题】:Why are signatures declared in the base class ignored?为什么忽略基类中声明的签名?
【发布时间】:2010-09-05 22:24:03
【问题描述】:
class Base
{
    public virtual void MethodA(int x)
    {
        Console.WriteLine ("In Base Class");
    }
}

class Derived : Base
{
    public override void MethodA(int x)
    {
        Console.WriteLine ("In derived INT)");
    }

    public void MethodA(object o)
    {
        Console.WriteLine ("In derived OBJECT");
    }
}

class Test
{
    static void Main()
    {
        Derived d = new Derived();
        int k = 20;
        d.MethodA(k);
    }
}

我得到的输出是“在派生的对象中”。这种奇怪行为的原因是什么?经过一番研究,我发现原因是在基类中声明的签名被忽略了。为什么他们会被忽视?

【问题讨论】:

  • +1 这个问题,我同意这是违反直觉的行为。
  • 我同意这种行为很奇怪。我想知道:你问这个是因为你真的想这样做还是因为你很好奇?我看不出实际实施这样的事情的理由,但我肯定想知道它为什么会发生。
  • 问题中的代码与此答案中的代码几乎相同:stackoverflow.com/questions/710459/…,所以你去吧。

标签: c# inheritance


【解决方案1】:

这是设计使然,并且有充分的理由。这种设计有助于防止脆性基类问题。 C# 旨在让编写“版本化”组件变得更容易、更安全,而这条规则是其中的重要组成部分。

这是一个非常常见的问题。这是我们得到的最常见的“错误错误报告”之一;也就是说,有人认为他们在编译器中发现了一个错误,而实际上他们发现了一个特性。

有关该功能的描述及其设计方式的原因,请参阅我关于该主题的文章:

http://blogs.msdn.com/b/ericlippert/archive/2007/09/04/future-breaking-changes-part-three.aspx

有关各种语言如何处理脆性基类问题的更多文章,请参阅我关于该主题的文章存档:

http://blogs.msdn.com/b/ericlippert/archive/tags/brittle+base+classes/

【讨论】:

    【解决方案2】:

    在决定调用什么时,VC# 2008 中的编译器会在虚拟函数之前检查可用的非虚拟函数。由于您的 Derived 类具有可以调用的非虚拟 MethodA(object),因此编译器会调用它。

    如果你向 Base 添加一个虚拟 MethodA(object),那么 Derived.MethodA(int) 将被调用,因为 MethodA(object) 和 MethodA(int) 都是虚拟的。

    我对 C# 语言规范不够熟悉,无法知道这是指定的行为,还是编译器中的错误。

    【讨论】:

    • 确实在ECMA规范中,将首先调用非虚拟。另请注意,被调用的方法由编译器确定非虚拟方法,以及虚拟方法的运行时类型。
    • 我检查了这个,但要注意 Derived.MethodA(int) 只有在您将关键字“覆盖”添加到 Derived.MethodA(object) 时才会被调用(这是当然的意思)。如果没有它,则假定可选关键字“new”并且 Derived.MethodA(object) 仍将被调用。
    猜你喜欢
    • 2020-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-25
    • 1970-01-01
    • 1970-01-01
    • 2021-04-05
    相关资源
    最近更新 更多