6

不确定这是否特定于 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);
  }
}

调用Fooin 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);
  }
}

调用Fooin 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)in Derived

Foo(object,DayOfWeek)从那时起如何调用Derived而不必在其中创建“冗余”方法Program

4

4 回答 4

6

我认为为了解决方法调用,它首先查看它的类,因为DayOfWeek可以作为object类型传递,它调用类自己的方法,而不是来自基类的方法。

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

来自 MSDN -方法解析。

如果派生类中的任何方法适用(第7.5.5.1节),则基类中的方法不是候选方法。

  • 给定一组适用的候选函数成员,找到该集合中的最佳函数成员。
  • 如果该集合仅包含一个函数成员,则该函数成员是最佳函数成员。
  • 否则,如果使用第 7.4.2.2 节中的规则将每个函数成员与所有其他函数成员进行比较,则最好的函数成员是在给定参数列表方面优于所有其他函数成员的一个函数成员。
  • 如果没有一个函数成员比所有其他函数成员更好,那么函数成员调用是不明确的,并且会发生编译时错误。
于 2012-09-03T05:21:21.887 回答
4

您需要查看 Eric Lippert 的博客 - 特别是这篇文章:http: //blogs.msdn.com/b/ericlippert/archive/2007/09/04/future-break-changes-part-three.aspx

但实际上,重载解析算法会在当前类中搜索可以调用的重载,并且仅在当前类中找不到替代方案时才在基类中搜索替代方案。

在第一种情况下,Foo(object, object)过载是适用的,因此不会执行进一步的搜索。

在第二种情况下Foo(object DayOfWeek)更好,所以它被使用。

阅读 Eric 的文章了解全部细节。

于 2012-09-03T05:27:01.717 回答
1

我认为规范是有道理的。派生类程序员不需要知道基类中非相对方法的实现。否则,一个倒霉的家伙写了一个比它的基类中的方法更不兼容的方法(而且这个家伙不知道基类的细节),然后调用基类中的方法。

于 2012-09-03T05:39:30.163 回答
1

正如其他人指出的那样,问题与重载解决方案的工作方式有关。只是补充一点:

如果Base.Foopublic,那么您可以这样做以到达Base.Foo内部Derived(假设Base.Foo没有被覆盖):

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

此外,您可以选择覆盖(如果您可以更改Base.Foovirtual)或显式隐藏,因此当您调用Base.Foowithin时,它仍然调用:Programbase.FooDerivedBase.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)> overrides Object.Equals(object)),或者它们只是给它一个不同的方法名称。

于 2012-09-03T07:23:59.930 回答