is关键字不能用于继承(baseClass是DerivedObject)= true"我怎么能避免这种情况"

Ton*_*Nam 2 c# polymorphism inheritance

我有课

Interface IVehicle
{
    int numberOfWheels;
    bool CanCross(string obstacle);
    // etc
}

class Car : IVehicle
{
    public int numberOfWheels = 4;
    public bool CanCross(string obstacle)
    {
       switch(obstacle) 
       {
          case "river":
              return false;
          case "grass":
              return true;
          // etc
       }
    }
}

class RaceCar: Car
{
    public int numberOfWheels = 4;
    public bool CanCross(string obstacle)
    {
       switch(obstacle) 
       {
          case "river":
              return false;
          case "grass":
              return false;
          // etc
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后我有方法:

 public object Foo(IVehicle vehicle, string obstacle)
 {                              
      if(vehicle.CanCross(obstacle)==false)
      {
          if(vehicle is Car)
             return Foo(new RaceCar(), obstacle);
          else if(vehicle is RaceCar)
             return Foo(new OldCar(), obstacle);
         // etc
          else
             return null;
      }

      // implementation

      return someObject;
 }
Run Code Online (Sandbox Code Playgroud)

请注意,如果车辆不能越过障碍物,我会再次使用相同的方法再次调用相同的方法,以尝试使用不同的车辆.我的问题是为什么如果vehicle = SpeedCar然后if (vehicle is Car)评估为?可能是因为它继承了它.我怎样才能检查车辆是否是SpeedCar而不是Car.我现在可以调用ToString()方法,然后执行正则表达式,但如果我重命名我的类,我将破坏我的代码...

换句话说,如果我通过的车辆无法穿越,而恰好是Car或SpeedCar,我将进入一个无限循环......

xxb*_*bcc 13

你可以使用is运算符来实现这一点- 事实上,它比使用它更快GetType().

你的继承层次结构是IVehicle- > Car- > RaceCar,所以任何一个RaceCar也将是a Car和a IVehicle.如果你首先测试基类,你的代码永远不会达到更具体的测试,因为基类无论如何都会匹配 - 这就是你遇到问题的原因.

在需要为继承链中的类执行不同操作的场景中测试的正确方法是首先测试更具体(更多派生)的类,然后测试基类.

if (vehicle is RaceCar)
{
    // code
}
else if (vehicle is Car)
{
    // code
}
else
{
    // code
}
Run Code Online (Sandbox Code Playgroud)

Dennis的回答是正确的,使用虚函数简化了这些情况,因为在大多数情况下,当你有虚函数时,你可以避免这种类型的测试 - 只需所有派生类都可以提供自己的函数实现(或者依赖于基本实现而不会覆盖它适当时).如果没有基础实现,您可以使用abstract关键字来指示派生类必须提供实现而不依赖于基类.那些派生类然后用于override实现这样的抽象函数.


Den*_*nis 9

我怎样才能检查车辆是否是SpeedCar而不是Car

vehicle.GetType() == typeof(SpeedCar)
Run Code Online (Sandbox Code Playgroud)


Oli*_*bes 8

虽然其他人已经回答了你的问题,但我想建议你另一种产生Foos的方法.使用多态来摆脱无穷无尽的if-else链(或switch语句)并让车辆实现一种方法CreateAlternateVehicle

public interface IVehicle
{
    bool CanCross(string obstacle);

    IVehicle CreateAlternativeVehicle();
}
Run Code Online (Sandbox Code Playgroud)

一个Car将创建一个RaceCar,一个RaceCar一个OldCar等.链中的最后一辆车可以返回null.作为一个例子,该类Car将像这样实现它:

public IVehicle CreateAlternativeVehicle()
{
    return new RaceCar();
}
Run Code Online (Sandbox Code Playgroud)

然后你的Foo创作就变成了

public object Foo(IVehicle vehicle, string obstacle)
{                              
    if(!vehicle.CanCross(obstacle)) {
        var altVehicle = vehicle.CreateAlternativeVehicle();
        if (altVehicle == null) {
            return null;
        }
        return Foo(altVehicle, obstacle);
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

通常,if-else链和switch语句是一个提示,可以用更面向对象的方式完成某些事情.