【问题标题】:Derived class using the wrong method使用错误方法的派生类
【发布时间】:2012-03-28 14:59:20
【问题描述】:

我已经将我的代码简化为这个

 internal class Program
{
    private static void Main(string[] args)
    {
        Child d = new Child();
        int i = 100;
        d.AddToTotal(i);

        Console.ReadKey();
    }

    private class Parent
    {
        public virtual void AddToTotal(int x)
        {
            Console.WriteLine("Parent.AddToTotal(int)");
        }
    }

    private class Child : Parent
    {
        public override void AddToTotal(int number)
        {
            Console.WriteLine("Child.AddToTotal(int)");
        }

        public void AddToTotal(double currency)
        {
            Console.WriteLine("Child.AddToTotal(double)");
        }
    }
}

问题是这调用了

public void AddToTotal(double currency)

虽然我用 int 调用它并且它应该使用

public override void AddToTotal(int number)

使用父级返回预期结果。

 Parent d = new Child();
 int i = 100;
 d.AddToTotal(i);

更新:

感谢@Jan 和@azyberezovsky 将我指向specification。我已经在基类中添加了一个虚拟空方法来解决这个问题。

【问题讨论】:

  • 嗯,我能够复制结果,并确保它不仅仅是 int 重载的方法名称不同的错字。
  • d.AddToTotal(number:i) 调用 int 重载,正如预期的那样,但你不应该这样做......
  • 查看这个答案以获得解释:stackoverflow.com/a/1833268/25727
  • 这个方法隐藏了吗?如果签名不一样,你能隐藏一个基本方法吗?

标签: c# inheritance overloading


【解决方案1】:

类型 T 中名称 N 的 member lookup 处理如下:

首先,构造在 T 中声明的所有名为 N 的可访问成员和 T 的基类型的集合。 包含 override 修饰符的声明从集合中排除如果不存在名为 N 且可访问的成员,则查找不产生匹配项,并且不评估以下步骤。

因此当你使用 Child 类型的变量时

Child d = new Child();
int i = 100;
d.AddToTotal(i);

方法public override void AddToTotal(int number) 被排除在集合之外,我们只剩下一个名称为N 的方法。 Int 被隐式转换为 double,因此没有发生错误。

【讨论】:

  • 我觉得很奇怪,重载决议会赋予新方法更高的优先级覆盖方法,但显然它确实......奇怪。有谁知道这背后的原因是什么?
  • @Servy 请参阅 Eric Lippert 的回答,原因是:stackoverflow.com/a/1833866/53777
  • @Servy:很多人觉得这个选择很奇怪,但有两个很好的理由。第一个原因是写派生类方法的开发者比写基类方法的开发者有更多的信息。具体来说,派生类开发者知道派生类的实现细节是什么,但基类开发人员没有。重载解决方案应该选择由最了解用户实际使用的对象的人编写的方法。
  • @Servy:第二,它防止了脆弱的基类失败的一种形式。详情请见blogs.msdn.com/b/ericlippert/archive/2007/09/04/…
  • @dnkulkarni:编译器选择在编译时调用哪个虚拟方法槽,那么它怎么能使用除了之外的任何东西编译时间类型?如果您想使用 runtime 类型,则将所有内容键入为“动态”。
【解决方案2】:

This answerthis question 解释了发生这种情况的技术原因。为方便起见,我在此处内嵌了答案,但所有功劳都归功于tvanfosson

请参阅Member Lookup 上的 C# 语言规范部分 和Overload Resolution。派生类的override方法 由于成员查找和基础规则,不是候选人 类方法不是基于重载解决方案的最佳匹配 规则。

第 7.3 节

首先,名为 N 的所有可访问(第 3.5 节)成员的集合 在 T 中声明并构造 T 的基本类型(第 7.3.1 节)。 包含覆盖修饰符的声明被排除在 放。如果不存在名为 N 且可访问的成员,则查找 产生不匹配,并且不评估以下步骤。

第 7.4.2 节:

这些上下文中的每一个都定义了一组候选函数成员 以及以自己独特的方式列出的参数,如 上面列出的部分中的详细信息。例如,集合 方法调用的候选者不包括标记的方法 覆盖(第 7.3 节),并且基类中的方法不是候选方法 如果派生类中的任何方法适用(第 7.5.5.1 节)。 (强调我的)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-24
    • 2012-05-31
    相关资源
    最近更新 更多