不知道这是否是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);
}
}
在Bar
中对Foo
的调用解析为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);
}
}
在Bar
中对Foo
的调用解析为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
中工作,但在Derived
中解析为Foo(object, object)
。
那么,如何从Derived
调用Foo(object,DayOfWeek)
,而不必在Program
中创建“冗余”方法?
4条答案
按热度按时间siv3szwd1#
我认为对于解析方法调用,它首先在它的类中查找,因为
DayOfWeek
可以作为object
类型传递,它调用类自己的方法,而不是基类的方法。在第二种情况下,方法调用解析为更特定的类型参数,因此
Foo(object bar, DayOfWeek day)
被调用。来自MSDN -Method resolution.
如果派生类中的任何方法都适用,则基类中的方法不是候选方法(第7.5.5.1节)。
wqnecbli2#
你需要看看埃里克·利珀特的博客-特别是这篇文章:https://learn.microsoft.com/en-us/archive/blogs/ericlippert/future-breaking-changes-part-three
不过,重载解析算法实际上是在当前类中搜索可以调用的重载,并且只在当前类中找不到重载时才在基类中搜索替代重载。
在第一种情况下,
Foo(object, object)
过载是适用的,因此不执行进一步的搜索。在第二种情况下,
Foo(object DayOfWeek)
更好,因此使用它。阅读Eric的文章了解详细信息。
gfttwv5a3#
我觉得这个规格很合理。派生类程序员不需要知道基类中 unrelative 方法的实现。否则,一个倒霉的家伙写了一个方法,它的兼容性比它的基类中的方法差(这个家伙不知道基类的细节),然后基类中的方法被调用。
zzoitvuj4#
正如其他人所指出的,这个问题与重载解决方案的工作方式有关。再补充一点:
如果
Base.Foo
是public
,那么你可以在Derived
中得到Base.Foo
(假设Base.Foo
没有被覆盖):此外,您可以选择覆盖(如果您可以将
Base.Foo
更改为virtual
)或在Program
中显式隐藏Base.Foo
,因此当您在Derived
中调用base.Foo
时,它仍然会调用Base.Foo
:作为旁注:* 通常 *,派生类提供的重载比它们的基类重载具有 * 更具体 * 的参数类型(例如,
Object.Equals(object)
,String.Equals(string)
)。即使有一个不太(或同样)具体的参数类型的情况下,他们要么 * 覆盖 * 基本方法(例如,
Object.Equals(object)
,String.Equals(object)
->重写Object.Equals(object)
),或者它们只是给予不同的方法名。