派生方法比 c# 中的重写更强
本文关键字:重写 方法 派生 | 更新日期: 2023-09-27 18:35:34
(又是一个烦人的问题...
之前问过这个问题后 - (部分与我的问题有关) - 我得到了答案:
请参阅 C# 4 规范的 §7.6.5.1:
候选方法集减少为仅包含来自 派生最多的类型:对于集合中的每个方法 C.F,其中 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:
吗?
子项具有父public void Foo(string strings)
的 1 个函数和一个 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"
}
那是因为你的孩子拿了一个物体。
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# 深度重载部分中读到了这一点
这里有两个概念被混淆了,重载和覆盖。 重载的概念是为同名的函数具有多个签名,并根据该签名选择一个签名进行调用。 重写是在派生类中重新定义方法的概念。
子类是否覆盖其中一个方法定义与调用哪个函数无关紧要,因为它不会更改任一方法的签名。 根据定义和构造,重写方法不能更改其签名。
因此,如果签名未更改,则对父类和子类使用完全相同的机制来确定基于签名调用的正确函数。
更新
事实上,正如埃里克·利珀特(Eric Lippert)在他的博客中指出的那样,还有更多的东西。 事实证明,如果有一个方法与子类中的重载匹配,它将不会在基类中查找任何方法。 原因是理智的 - 避免中断性更改 - 但是当您同时拥有基类和子类时,结果有些不合逻辑。
我只能附和乔恩·斯基特(Jon Skeet)的话:"鉴于这种奇怪之处,我的建议是避免跨越继承边界的过载......至少对于多个方法可能适用于给定调用的方法,如果您扁平化层次结构"
你在这里看到 最佳匹配规则 .
将参数等string
传递给Foo(..)
函数。
基类有Foo(string..)
,子类没有。所以在这种情况下,最终选择了碱的方法。
我认为这里的基类方法是根据其dataType
选择
由于c.Foo("d");
与基类方法完全匹配,并且derived class
中没有任何方法被重写,因此调用基类方法。