【问题标题】:Overload resolution oddity过载分辨率异常
【发布时间】:2012-09-03 05:18:01
【问题描述】:

不确定这是否特定于 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 中创建“冗余”方法?

【问题讨论】:

    标签: c# .net overload-resolution


    【解决方案1】:

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

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

    来自 MSDN - Method resolution.

    如果派生类中有任何方法,则基类中的方法不是候选方法 类适用7.5.5.1部分)。

    • 给定一组适用的候选函数成员,找到该集合中的最佳函数成员。
    • 如果集合仅包含一个函数成员,则该函数成员是最佳函数成员。
    • 否则,最好的函数成员是比所有其他函数成员在给定的方面更好的一个函数成员 参数列表,前提是每个函数成员都与所有 使用第 7.4.2.2 节中的规则的其他函数成员。
    • 如果没有一个函数成员优于所有其他函数成员,则函数成员调用是 模棱两可并且发生编译时错误。

    【讨论】:

    • 我理解它看似试图做什么,但这意味着具有“对象”参数的那个将否决所有其他重载,并且无法调用基类中的任何特定重载,其中turn 使得继承非常有限并且容易出错。
    • 谢谢,找到了“法律”。 如果派生类中的任何方法适用,则基类中的方法不是候选方法。所以这是正常的... :*(
    • @lippie,我正要从同一个链接引用它:)
    • 至于我的问题。您可以通过在调用中添加base. 来强制调用基类。至少打电话给他们是可能的:)
    • @leppie 或者你可以给方法一个不同的名字
    【解决方案2】:

    您需要查看 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 的文章了解完整详情。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 我的问题更多在于如何实际调用(或特定的)基本实现(给定指定的分辨率)。 base. 在某些情况下会有所帮助,但在进一步的派生类中会失败。
      【解决方案4】:

      正如其他人所指出的,问题与重载解析的工作方式有关。补充一点:

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

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

      此外,您可以选择覆盖(如果您可以将Base.Foo 更改为virtual)或在Program 中显式隐藏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)),或者他们只是给它一个不同的方法名称。

      【讨论】:

      • public 上的有趣发现。我想知道为什么它在protected 时不起作用,即使我在派生类中。
      • @leppie 因为编译器不知道((Base)this) 引用的对象是Derived。据它所知,它可能指的是Program2 的一个实例,它也派生自Base。如果是这种情况,您将无法从Derived 中访问Program2.Foo。见here
      猜你喜欢
      • 2013-08-20
      • 2011-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-04
      • 2019-12-16
      相关资源
      最近更新 更多