4

又是一个烦人的问题……

在之前问过这个之后 - (这部分与我的问题有关) - 我得到了答案:

请参阅 C# 4 规范的第 7.6.5.1 节:

候选方法集减少为仅包含来自最派生类型的方法:对于集中的每个方法 CF,其中 C 是声明方法 F 的类型,从 C 的基类型中声明的所有方法都将从中删除集。

行。

我有这个代码://.Dump() is like a WriteLine command...

 public class Base
    {
        public void Foo(string strings)  { "1".Dump();}
        public virtual void  Foo(object strings)  { "2".Dump();}
    }

    public class Child : Base
    {

        public override void  Foo(object strings)  { "4".Dump();}
    }

但是这段代码:

Child c = new Child();
c.Foo("d");

发出:"1"

可是等等 ...

我们不是说过is reduced to contain only methods from the most derived types:吗?

Child 有 1 个来自其父亲的函数public void Foo(string strings)和一个NEARER 覆盖函数

那么他为什么选择它的基地功能呢?继承的函数是否比覆盖更接近?

是否与覆盖在运行时有关?

请帮忙。

编辑

这种情况呢?

public class Base
    {    
        public virtual void  Foo(int x)  { "1".Dump();}
    }

    public class Child : Base
    {
        public override void  Foo(int x)  { "2".Dump();}
        public void Foo(object x) { "3".Dump();}    
    }

void Main()
{
    Child c = new Child();
    c.Foo(6); //emits "3"
}
4

4 回答 4

6

那是因为你的孩子拿了一个物体。

public class Child : Base
{
    public override void Foo(object strings)  { "4".Dump();}
}

使其成为字符串,然后将调用子项。

public class Child : Base
{
    public override void Foo(string strings)  { "4".Dump();}
}

为什么这个?

因为编译器看到孩子有object参数,所以在基类中它必须转换string为字符串,它很容易作为字符串使用。

所以它称基数为一。

虽然覆盖函数在子类中更接近。但是这里的规则在孩子和基地是不同的。孩子有对象,基地有字符串。如果两者都有object或两者都有,这是公平的string.

我在 Jon Skeet 的C# in Depth Overloading 部分读到了这个

于 2012-05-28T07:35:31.303 回答
3

这里有两个概念被混淆,重载和覆盖。重载是为同名函数提供多个签名并根据该签名选择一个来调用的概念。覆盖是在派生类中重新定义方法的概念。

子类是否覆盖其中一个方法定义与调用哪个函数完全无关,因为它不会更改任一方法的签名。根据定义和构造,重写方法不能更改它的签名

因此,如果签名未更改,则基于签名确定要调用的正确函数的机制将用于父类和子类。

更新

事实上,正如 Eric Lippert 在他的博客中指出的那样,它还有更多内容。事实上,如果子类中存在与重载匹配的方法,它将不会在基类中查找任何方法。原因是理智的——避免破坏性的变化——但是当你同时拥有基类和子类时,结果有点不合逻辑。

我只能附和 Jon Skeet:“鉴于这种奇怪,我的建议是避免跨越继承边界重载……至少对于如果你扁平化层次结构,一个给定调用可能适用于多个方法的方法”

于 2012-05-28T07:45:54.673 回答
1

您在此处看到 最佳匹配规则

您将string类似的参数传递给Foo(..)函数。

基类有一个Foo(string..),子类,相反,没有。因此,在这种情况下,最终选择了 base 的方法。

于 2012-05-28T07:35:57.810 回答
1

我认为这里的基类方法是根据它的dataType

Asc.Foo("d");与基类方法完全匹配,并且没有任何方法被覆盖,derived class因此调用了基类方法。

于 2012-05-28T07:36:00.657 回答