C# 超负荷分辨奇异性
不确定这是否是C#4+特有的,但只是注意到了这一点 考虑以下类别:C# 超负荷分辨奇异性,c#,.net,overload-resolution,C#,.net,Overload Resolution,不确定这是否是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); } } 在Ba
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(对象,对象)
将其更改为:
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(对象,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.
调用在程序中起作用,但随后在派生的中解析为Foo(对象,对象)
一个调用Foo(object,DayOfWeek)
如何从派生而不必在Program
中创建“冗余”方法呢?我认为对于解析方法调用,它首先在类中查找,因为DayOfWeek
可以作为对象
类型传递,它调用类自己的方法,不是来自基类的那个
在第二种情况下,方法调用解析为更特殊的类型参数,因此调用Foo(对象栏,DayOfWeek-day)
从MSDN-
如果派生类中有任何方法,则基类中的方法不是候选方法
类别适用(第节)
- 给定一组适用的候选函数成员,将找到该集合中的最佳函数成员
- 如果集合仅包含一个函数成员,则该函数成员是最佳函数成员
- 否则,最好的函数成员是相对于给定函数优于所有其他函数成员的一个函数成员
参数列表,前提是将每个函数成员与所有
使用第7.4.2.2节规则的其他职能成员
- 如果没有一个函数成员优于所有其他函数成员,则函数成员调用是
不明确,出现编译时错误
您需要查看Eric Lippert的博客,尤其是本文:
实际上,重载解析算法在当前类中搜索可以调用的重载,并且只在当前类中找不到替代的基类时搜索替代的重载
在第一种情况下,Foo(object,object)
重载适用,因此不执行进一步的搜索
在第二种情况下,Foo(objectdayofweek)
更好,因此使用它
请阅读Eric的文章了解全部细节。我认为规范是有意义的。派生类程序员不需要知道非相关方法在基类中的实现。否则,一个倒霉的家伙写了一个比基类中的方法兼容性差的方法(这个家伙不知道基类的细节),然后调用基类中的方法 正如其他人所指出的,问题与过载解决方案的工作方式有关。除此之外:
如果Base.Foo
是public
,那么您可以这样做以在Derived
中访问Base.Foo
(假设Base.Foo
未被覆盖):
此外,您还可以选择覆盖(如果您可以将Base.Foo
更改为virtual
)或在程序中显式隐藏Base.Foo
,因此当您在Derived
中调用Base.Foo
时,它仍然调用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)
)
即使存在较少(或同等)特定参数类型的情况,它们也会覆盖基本方法(例如Object.Equals(Object)
,String.Equals(Object)
->覆盖Object.Equals(Object)
),或者只给它一个不同的方法名称 我理解它似乎在做什么,但这意味着带有“object”参数的将否决所有其他重载,并且无法调用基类中的任何特定重载,这反过来会使继承非常有限且容易出错。谢谢,找到了“定律”。如果派生类中的任何方法都适用,则基类中的方法不是候选方法。所以这是正常的…:*(@lippie,我正要引用同一链接:)至于我的次要问题。您可以通过向调用中添加base.
来强制调用基类。至少调用它们仍然是可能的:)@leppie或者您可以给该方法一个不同的名称。我的问题更多地在于如何实际调用(或特定的)基本实现(给定特定的分辨率)<代码>基。
在某些情况下有帮助,但在进一步的派生类中失败。在public
上有一个有趣的发现。我想知道为什么即使我在派生类中,当它受到保护时它也不能工作。@leppie因为编译器没有足够的智慧知道((Base)this)
引用的对象是派生的。据它所知,它可能是指Program2
的一个实例,该实例也派生自Base
。如果是这种情况,则不允许您从派生的中访问Program2.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);
}
}