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

问题描述 投票:3回答:1

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

首先,我们有一个基类A,它定义了一个名为Foo的虚函数,它接受一个参数。

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

然后是一个覆盖Foo的B类,它为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”)。我认为这种带有默认参数的虚函数重载会导致编译器错误,但编译错误。

有没有办法解决这个问题,如果不是为什么它允许类的结构阻止我访问基本方法?

c# inheritance override overloading virtual
1个回答
3
投票

这是可选参数与语言其余部分之间的不幸交互,这是一个很好的理由,为什么你基本上不应该重载使用可选参数的方法(或者将重载添加到不使用的方法)。 B的作者做了一些非常糟糕的事情!

调用不是模糊的,因为方法查找的规则不会改变base,只有在重载解析后最终调用哪个方法的规则 - 实际上,重载被确定为调用已经读取了((C) this).Foo(0)。对于那个调用,B.Foo(int, int, int)被认为是唯一的候选者,因为它是走近继承链时最接近的非override方法 - 它在我们考虑A.Foo(int)之前被选中。如果A介绍了这种方法,就没有问题,因为在这种情况下,单参数重载会被认为是更好的方法。

如果可选参数从一开始就是C#的一部分,而不是派对的相对较晚的添加(有一些奇怪的实现,其中值在呼叫站点扩展),这可能已被考虑并以某种方式减轻。目前最明显的解决方法是通过实际更改base查找的规则,使其更喜欢匹配与其出现的方法的签名完全匹配的方法,但这会使已经复杂的重载规则复杂化甚至更多,它肯定会破坏现有的代码,所以这种事情发生的可能性很小。

如果你不能改变ABC,仍然有办法编写D以获得所需的行为,通过利用(如果这个词)另一个相当模糊的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)

© www.soinside.com 2019 - 2024. All rights reserved.