3

我有课

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

然后我有方法:

 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;
 }

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

换句话说,如果我通过的车辆无法通过并且它恰好是汽车或 SpeedCar,我将进入无限循环......

4

4 回答 4

16

您可以使用运算符来执行此is操作 - 实际上,它比使用GetType().

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

在需要为继承链中的类做不同事情的场景中进行测试的正确方法是首先测试更具体(更多派生)的类,最后测试基类。

if (vehicle is RaceCar)
{
    // code
}
else if (vehicle is Car)
{
    // code
}
else
{
    // code
}

丹尼斯的回答是正确的,使用虚函数可以简化这些情况,因为在大多数情况下,当您拥有虚函数时,您可以避免此类测试 - 只是所有派生类都可以提供自己的函数实现(或依赖基本实现而不覆盖在适当的时候使用)。如果有一个基实现没有意义,您可以使用abstract关键字来指示派生类必须提供一个实现而不依赖于基类。然后这些派生类override用于实现这些抽象函数。

于 2012-09-18T19:23:14.537 回答
11

我如何检查车辆是否是 SpeedCar 但不是汽车

vehicle.GetType() == typeof(SpeedCar)
于 2012-09-18T19:08:50.777 回答
8

虽然其他人已经回答了您的问题,但我想向您推荐另一种生成 Foos 的方法。使用多态性摆脱无休止的 if-else 链(或 switch 语句),让车辆实现一个方法CreateAlternateVehicle

public interface IVehicle
{
    bool CanCross(string obstacle);

    IVehicle CreateAlternativeVehicle();
}

ACar将创建 a RaceCar, a RaceCaranOldCar等等。链条中的最后一辆车可以返回null。例如,该类Car将像这样实现它:

public IVehicle CreateAlternativeVehicle()
{
    return new RaceCar();
}

然后你的 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);
    }
    ...
}

很多时候,if-else 链和 switch 语句是一种暗示,可以以更面向对象的方式完成某些事情。

于 2012-09-18T19:49:46.720 回答
-2

您应该只检查是否(车辆是 RaceCar)

于 2012-09-18T19:08:05.113 回答