重载分辨率奇怪

时间:2012-09-03 05:18:01

标签: 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);
  }
}

FooBar的来电,解析为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);
  }
}

FooBar的来电,解析为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中创建“冗余”方法?

4 个答案:

答案 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.Foopublic,那么您可以执行此操作以转到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)),或者只是给它一个不同的方法名称。