C#派生类,重载解析

时间:2010-08-05 20:33:25

标签: c# overloading derived-class

好的,我有一些从基类派生的不同对象,我把它们放在一个列表中。我想遍历列表并将每个推送到一个方法。我对每个类型的签名都有单独的方法,但编译器抱怨。有人可以解释原因吗?这是一个使用泛型的机会,如果是的话,怎么样?

class Base { }
class Level1 : Base { }
class Level2 : Level1 { }

...

List<Base> oList = new List<Base>();
oList.Add(new Level1());
oList.Add(new Level2());

...

...
foreach(Base o in oList)
{
   DoMethod(o);
}

...

void DoMethod(Level1 item) { }
void DoMethod(Level2 item) { }

我做错了什么?

8 个答案:

答案 0 :(得分:7)

重载在编译时解决 - 并且您没有DoMethod(Base item)方法 - 因此无法解析调用。离开列表和循环,你有效地写作:

Base o = GetBaseFromSomewhere();
DoMethod(o);

编译器必须找到一个名为DoMethod的方法,该方法适用于Base类型的单个参数。没有这样的方法,因此失败了。

这里有几个选项:

  • 正如Markos所说,您可以使用C#4中的动态类型,使用实际类型的对象{{1}使C#编译器在执行时应用重载}指的是。
  • 您可以使用Visitor Pattern有效地获得双重发送(我从未真正喜欢过这种情况)
  • 您可以使用oas

    is

    再次,这非常难看

  • 重新设计您正在做的事情,以便能够使用正常继承,如果可能的话

答案 1 :(得分:2)

重载方法使用变量的静态类型而不是运行时类型。

您想使用inheritence和覆盖

class Base { public virtual void DoMethod() { /* ... */  } }
class Level1 : Base { public override void DoMethod() { /* ... */ } }
class Level2 : Level1 { public override void DoMethod() { /* ... */ } }

答案 2 :(得分:1)

调用哪个方法是在编译时而不是运行时确定的,因此编译器无法知道要调用哪个方法。你有2个选择: 切换对象的类型并调用适当的方法,或 如果您使用的是.NET 4,请使用type dynamic。

foreach(dynamic o in oList)
{
   DoMethod(o);
}

答案 3 :(得分:1)

您没有DoMethod(基本项)方法。重载不是多态的。这通常通过使用虚拟方法完成:

class Base {
    public virtual void DoMethod() {...}
}
class Level1 : Base {
    public override void DoMethod() {...}
}
// etc..

foreach(Base o in oList)
{
    o.DoMethod();
}

答案 4 :(得分:1)

在您的foreach循环中,o的类型为Base,而DoMethod重载都没有Base个实例。如果可能,您应该将DoMethod移至Base并在两个子类中覆盖它:

public class Base
{
    public virtual void DoMethod() { ... }
}

答案 5 :(得分:1)

要扩展Mark的答案,DoMethod应该是Base中的虚拟方法,您可以在列表中的每个项目上调用它。

答案 6 :(得分:0)

我不知道所有的细节,但如果它真的不适合继承你可以使用接口。

声明接口,在每个类上实现它,然后你就可以直接转换到接口并从那里运行函数。我的C#有点不稳定,但有点像,

Interface IMethodizable
{
   void DoMethod();
}

class Level1 : IMethodizable {
  void DoMethod(){
    //insert code here
  }
}

class Level2 : IMethodizable {
  void DoMethod(){
    //insert code here
  }
}

如果这个类的唯一共同点是那个方法,那么效果特别好。这与在基类中使用虚拟化方法并覆盖它非常相似。所以这种模式只有在你不应该继承时才会更好,或者DoMethod也必须在不继承base等的其他对象上运行。

答案 7 :(得分:0)

由于C#7.0模式匹配是另一种选择。

有关更多信息,请参见MSDN。 您的代码想要:

switch(o)
{
    case Level2 level2: Do(level2); break;
    case Level1 level1: Do(level1); break;
    case Base @base: Do(@base); break;
    default: ...
    case null: ...
}