不确定这是否是C#4+特定的,但只是注意到了这一点。
考虑以下课程:
class Base
{
protected void Foo(object bar, DayOfWeek day)
{
}
}
class Program : Base
{
protected void Foo(object bar, object baz)
{
}
void Bar(DayOfWeek day)
{
Foo(new { day }, day);
}
}
Foo
对Bar
的来电,解析为Foo(object, object)
。
将其更改为:
class Base
{
}
class Program : Base
{
protected void Foo(object bar, object baz)
{
}
protected void Foo(object bar, DayOfWeek day)
{
}
void Bar(DayOfWeek day)
{
Foo(new { day }, day);
}
}
Foo
对Bar
的来电,解析为Foo(object, DayOfWeek)
。
我的理解是它应该像第二个例子一样解决。
这是一个'错误'还是我缺乏理解(或无知)?
更新:
感谢您的回答。我已经发现,可以使用base.
来调用基类中的方法。然而,当在混合中添加另一个派生类时,问题就出现了。
class Base
{
protected void Foo(object bar, DayOfWeek day)
{
}
}
class Program : Base
{
protected void Foo(object bar, object baz)
{
}
void Bar(DayOfWeek day)
{
base.Foo(new { day }, day);
}
}
class Derived : Program
{
void Baz(DayOfWeek day)
{
base.Foo(new { day }, day);
}
}
base.
调用适用于Program
,但后来解析为Foo(object, object)
中的Derived
。
如何从Foo(object,DayOfWeek)
拨打Derived
,而无需在Program
中创建“冗余”方法?
答案 0 :(得分:6)
我认为对于解析方法调用它首先在其类中查找,因为DayOfWeek
可以作为object
类型传递,它调用类自己的方法,而不是基类中的方法。
在第二种情况下,方法调用解析为更具体的类型参数,因此调用Foo(object bar, DayOfWeek day)
。
来自MSDN - Method resolution.
如果派生中的任何方法,基类中的方法都不是候选方法 课程适用
(第7.5.5.1部分)。
- 给定一组适用的候选函数成员,找到该集合中最好的函数成员。
- 如果集合只包含一个函数成员,那么该函数成员是最好的函数成员。
- 否则,最好的函数成员是一个函数成员,它比给定的所有其他函数成员更好 参数列表,前提是将每个函数成员与所有函数成员进行比较 其他函数成员使用第7.4.2.2节中的规则。
- 如果没有一个函数成员优于所有其他函数成员,则函数成员调用为 发生模糊和编译时错误。
答案 1 :(得分:4)
你需要查看Eric Lippert的博客 - 尤其是这篇文章:http://blogs.msdn.com/b/ericlippert/archive/2007/09/04/future-breaking-changes-part-three.aspx
但实际上,重载解析算法会在当前类中搜索可以调用的重载,并且只在当前类中找不到替代类时才搜索基类。
在第一种情况下,Foo(object, object)
重载适用,因此不再执行进一步搜索。
在第二种情况下,Foo(object DayOfWeek)
更好,因此使用它。
阅读Eric的文章了解详情。
答案 2 :(得分:1)
我认为该规范是有道理的。派生类程序员不需要知道基类中的无关方法的实现。否则,一个不幸的人编写了一个方法,其兼容性低于其基类中的方法(并且这个人不知道基类的细节),然后调用基类中的方法。
答案 3 :(得分:1)
正如其他人所指出的,问题与重载解析的工作方式有关。只是补充一点:
如果Base.Foo
为public
,那么您可以执行此操作以转到Base.Foo
内的Derived
(假设Base.Foo
未被覆盖):
((Base)this).Foo(new { day }, day);
此外,您可以选择覆盖(如果您可以将Base.Foo
更改为virtual
)或明确隐藏Base.Foo
Program
,以便致电{{1在base.Foo
内,它仍然会调用Derived
:
Base.Foo
作为旁注:
通常,派生类提供了更具体的参数类型的重载,而不是基类重载(例如class Program : Base
{
protected void Foo(object bar, object baz)
{
}
protected new void Foo(object bar, DayOfWeek baz)
{
base.Foo(bar, baz);
}
void Bar(DayOfWeek day)
{
base.Foo(new { day }, day);
}
}
,Object.Equals(object)
)。
即使存在较少(或同等)特定参数类型的情况,他们也覆盖基本方法(例如String.Equals(string)
,{{1} } - >覆盖Object.Equals(object)
),或者只是给它一个不同的方法名称。