其他分享
首页 > 其他分享> > 带有多个重载和默认参数的特定基本方法的调用

带有多个重载和默认参数的特定基本方法的调用

作者:互联网

我基于游戏的源代码构建,并尝试使用重载方法和默认参数调用基本虚拟函数.我无法更改派生的类,需要在我自己的虚拟方法的类定义中调用该函数.我将尝试用代码更详细地解释.

首先,我们有一个基类A,它定义了一个称为Foo的虚拟函数,该函数带有一个参数.

class A
{
   public virtual string Foo(int a)
   {
      return "Class A Function 1 par";
   }
}

然后,一个类B覆盖Foo,并使用两个新的默认参数为Foo定义了一个新的重载虚拟函数.

class B : A
{
   public virtual string Foo(int a, int b = 0, int c = 0)
   {
      return "Class B Function 3 par";
   }

   public override string Foo(int a)
   {
      return "Class B Function 1 par";
   }
}

然后,我需要从C派生该类.它只是覆盖了一个参数Foo.

class C : B
{
   public override string Foo(int a)
   {
      return "Class C Function 1 par";
   }
}

最后,我的类D也重写了一个参数Foo,但还需要能够调用Foo的基本方法.

class D : C
{
   public override string Foo(int a)
   {
      return base.Foo(0);
   }
}

这导致调用B中定义的三个参数Foo(返回为“ Class B Function 3 par”),但我想调用C中定义的Foo(将返回“ Class C Function 1 par”).我认为这种带有默认参数的虚拟函数重载会导致模棱两可的编译器错误,但编译良好.

有没有一种方法可以解决此问题,如果不能解决,为什么要允许类的结构将我锁定为无法访问基本方法?

解决方法:

这是可选参数与语言其余部分之间的不幸交互,这是为什么您基本上不应该重载使用可选参数的方法(或向未使用可选参数的方法添加重载)的一个很好的理由. B的作者所做的事情确实很糟糕!

调用不是模棱两可的,因为方法查找的规则不会针对基数进行更改,只有在重载解析后最终调用该方法的规则-实际上,重载的确定就像调用已读取((C )this).Foo(0).对于该调用,B.Foo(int,int,int)被认为是唯一的候选方法,因为它是在继承链上最接近的非重写方法-在我们甚至考虑A.Foo(int)之前就已经选择了它. ).如果A引入了该方法,就不会有问题,因为在那种情况下,单参数过载将被认为是一种更好的方法.

如果从一开始就将可选参数作为C#的一部分,而不是相对较晚地添加到该方(有些古怪的实现,即在调用站点上扩展值),则可以考虑并以某种方式缓解这种情况.到目前为止,解决此问题的最明显方法是实际更改基础查找的规则,因此它更喜欢匹配与出现的方法签名完全匹配的方法,但这只会使已经复杂的重载规则复杂化甚至更多,而且它肯定会破坏现有代码,因此发生这种情况的可能性很小.

如果您无法更改A,B和C,则仍然可以通过利用(如果是这样的话)编写另一个D来获得所需的行为的方法,该C甚至更老的C#功能:方法组!

class D : C
{
   public override string Foo(int a) 
   {
      Func<int, string> foo = base.Foo;
      return foo(a);
   }
}    

这明确地调用了C.Foo(int),因为方法组上的委托转换不考虑可选参数,因此B.Foo(int,int,int)不是有效的候选者,这迫使我们往上走并查找A.Foo(int).

标签:inheritance,overloading,virtual,override,c
来源: https://codeday.me/bug/20191108/2005646.html