C#派生类,重载解析

问题描述 投票:5回答:8

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

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) { }

我究竟做错了什么?

c# overloading derived-class
8个回答
7
投票

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

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

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

这里有几个选项:

  • 正如Markos所说,您可以在C#4中使用动态类型来使C#编译器在执行时使用o引用的实际对象类型来应用重载。
  • 你可以使用Visitor Pattern有效地获得双重调度(我从来没有真正喜欢这个)
  • 你可以使用asisLevel1 x = o as Level2; if (x != null) { DoMethod(x); // Resolves to DoMethod(Level1) } else { Level2 y = o as Level2; if (y != null) { DoMethod(y); // Resolves to DoMethod(Level2) } } 再次,这非常难看
  • 如果可能的话,重新设计你正在做的事情,以便能够使用正常继承

2
投票

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

您想使用继承和覆盖。

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

2
投票

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

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

1
投票

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

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

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

1
投票

在你的foreach循环中,o具有Base类型,并且DoMethod重载都没有采用Base实例。如果可能的话,你应该将DoMethod移动到Base并在两个子类中覆盖它:

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

1
投票

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


0
投票

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

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

Interface IMethodizable
{
   void DoMethod();
}

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

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

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


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: ...
}
© www.soinside.com 2019 - 2024. All rights reserved.