重载解析怪胎(Overload resolution oddity)

2019-09-22 02:22发布

不知道这是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

Answer 1:

我认为解决的方法调用,它看起来在同级车第一,因为DayOfWeek可以作为传递object类型,它调用类自己的方法,而不是从基类中的一个。

在第二种情况下,该方法调用解析为一个更特定类型参数,因此Foo(object bar, DayOfWeek day)被调用。

从MSDN - 方法解析。

基类的方法不是候选如果在派生类的任何方法都是适用的 (见第7.5.5.1 )。

  • 给定了适用的候选函数成员,在该集合最好的函数成员。
  • 如果集合中只包含一个函数成员,则该函数成员为最佳函数成员。
  • 否则,最佳函数成员是一个函数成员比相对于给定的参数列表中的所有其他函数成员更好,每个函数成员与使用规则第7.4.2.2其他功能成员提供。
  • 如果不是正好有一个函数成员比所有其他函数成员都好,则函数成员调用不明确并发生编译时错误。


Answer 2:

你需要签埃里克利珀的博客-尤其是这篇文章: http://blogs.msdn.com/b/ericlippert/archive/2007/09/04/future-breaking-changes-part-three.aspx

虽然有效,重载解析算法搜索,可以调用过载电流类,只有当在当前类中没有找到一个搜索基类的替代品。

在第一种情况下Foo(object, object)超载是适用所以不执行进一步的搜索。

在第二种情况下, Foo(object DayOfWeek)是更好的,从而它被使用。

阅读Eric的为全细节的文章。



Answer 3:

我认为规范是有道理的。 派生类程序员不需要知道unrelative方法在基类的实现。 否则,一个倒霉的家伙写了一个方法,用一个比其基类(这家伙不知道基类的细节),在基类中的方法被调用再少compatiable。



Answer 4:

正如其他人所指出的,这个问题是关系到道路重载决议的作品。 我想补充到:

如果Base.Foopublic ,那么你可以做到这一点去Base.FooDerived (假设Base.Foo是未覆盖):

((Base)this).Foo(new { day }, day);

此外,你必须重写(如果你可以改变的选项Base.Foovirtual )或明确隐藏Base.Foo内的Program ,所以当你打电话base.FooDerived ,它仍然呼吁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) ),或他们只是给它一个不同的方法名。



文章来源: Overload resolution oddity