简体   繁体   English

C#派生类,重载解析

[英]C# derived classes, overload resolution

Ok, I have an some different objects that are derived from a base class and I've put a bunch of them in a list. 好吧,我有一些从基类派生的不同对象,我把它们放在一个列表中。 I want to loop through the list and push each to a method. 我想遍历列表并将每个推送到一个方法。 I have separate methods with each one's type signature, but the compiler is complaining. 我对每个类型的签名都有单独的方法,但编译器抱怨。 Can someone explain why? 有人可以解释原因吗? Is this an opportunity to use Generics, and if so, how? 这是使用泛型的机会,如果是的话,怎么样?

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

What am I doing wrong? 我究竟做错了什么?

Overloads are resolved at compile-time - and you don't have a DoMethod(Base item) method - so it can't resolve the call. 重载在编译时解决 - 并且您没有DoMethod(Base item)方法 - 因此它无法解析调用。 Leaving the list and the loop out of things, you're effectively writing: 离开列表和循环,你有效地写:

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

The compiler has to find a method called DoMethod which is applicable for a single argument of type Base . 编译器必须找到一个名为DoMethod的方法,该方法适用于Base类型的单个参数。 There is no such method, hence the failure. 没有这样的方法,因此失败了。

There are a few options here: 这里有几个选项:

  • As Markos says, you can use dynamic typing in C# 4 to make the C# compiler apply overloading at execution time using the actual type of object that o refers to. 正如Markos所说,你可以在C#4中使用动态类型来使C#编译器在执行时使用o引用的实际类型的对象来应用重载。
  • You can use the Visitor Pattern to effectively get double dispatch (I'm never really fond of this) 你可以使用访客模式有效地获得双重调度(我从来没有真正喜欢这个)
  • You can use as or is : 您可以使用as或者is

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

    Again, this is pretty ugly 再次,这非常难看

  • Redesign what you're doing to be able to use normal inheritance, if possible 如果可能的话,重新设计你正在做的事情,以便能够使用正常继承

Overloading a method uses the static type of the variable not the run time type. 重载方法使用变量的静态类型而不是运行时类型。

You want to use inheritence and overriding . 您想使用继承和覆盖

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

Which method is called is determined in Compile time not runtime, so the compiler cannot know which one to call. 在Compile time而不是运行时确定调用哪个方法,因此编译器无法知道要调用哪个方法。 You have 2 options: Switch over type of the object and call apropriate method, or if you are using .NET 4, use type dynamic. 您有两个选项:切换对象的类型并调用适当的方法,或者如果您使用的是.NET 4,请使用类型dynamic。

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

You don't have a DoMethod(Base item) method. 您没有DoMethod(基本项)方法。 Overloading is not polymorphic. 重载不是多态的。 This is normally done by using a virtual method: 这通常通过使用虚拟方法完成:

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

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

In your foreach loop, o has type Base and neither of the DoMethod overloads take a Base instance. 在foreach循环中, o具有Base类型,并且DoMethod重载都不会占用Base实例。 If possible you should move DoMethod to Base and override it in the two subclasses: 如果可能,您应该将DoMethod移动到Base并在两个子类中覆盖它:

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

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

I don't know all the details, but if it's a situation where it really isn't appropriate to inherit you could use interfaces instead. 我不知道所有的细节,但如果它真的不适合继承你可以使用接口。

Declare the interface, implement it on each of your classes, then you would be able to cast directly to the interface and run the function from there. 声明接口,在每个类上实现它,然后你就可以直接转换到接口并从那里运行函数。 My C# is a little shaky, but something like, 我的C#有点不稳定,但有点像,

Interface IMethodizable
{
   void DoMethod();
}

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

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

This works particularly well if the only thing the classes have in common are that method. 如果这个类的唯一共同点就是该方法,那么这种方法效果特别好。 This is very similar to having a virtualized method int he base class and overriding it. 这与在基类中使用虚拟化方法并覆盖它非常相似。 So this pattern is only better if you shouldn't be inheriting, or the DoMethod will also have to run on other objects not inheriting from base, et al. 所以这个模式只有在你不应该继承时才会更好,或者DoMethod也必须在不继承base等的其他对象上运行。

Since C# 7.0 pattern-matching is another option. 由于C#7.0模式匹配是另一种选择。

For more information see MSDN . 有关更多信息,请参阅MSDN Your code would like like: 你的代码喜欢:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM