【问题标题】:is keyword does not work with inheritance ( baseClass is DerivedObject ) = true "How could I avoid that"is 关键字不适用于继承(基类是派生对象)= true “我怎么能避免这种情况”
【发布时间】:2012-09-18 19:04:01
【问题描述】:

我有课

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() 方法然后执行正则表达式,但是如果我重命名我的类,我会破坏我的代码...

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

【问题讨论】:

    标签: c# inheritance polymorphism


    【解决方案1】:

    您可以使用 is 运算符来执行此操作 - 事实上,它比使用 GetType() 快一些。

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

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

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

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

    【讨论】:

      【解决方案2】:

      如何检查车辆是否是 SpeedCar 而不是 Car

      vehicle.GetType() == typeof(SpeedCar)
      

      【讨论】:

      • @TonoNam:不客气。顺便说一句,你真的不应该隐藏继承的成员CanCross。设为virtual 并使用override 关键字覆盖后代类中的行为。另外,为了抛弃丑陋的类型检查,你可以添加一个虚拟属性Car.ReplaceWithCar
      • 那么您的方法Foo 将如下所示:if (!car.CanCross(obstacle)) { return car.ReplaceWithCar != null ? Foo(car.ReplaceWithCar) : null; }
      • 谢谢,我会把它虚拟化或抽象化。
      【解决方案3】:

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

      public interface IVehicle
      {
          bool CanCross(string obstacle);
      
          IVehicle CreateAlternativeVehicle();
      }
      

      Car 将创建 RaceCarRaceCarOldCar 等等。链中的最后一辆车可以返回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 语句通常是一种暗示,表明可以以更面向对象的方式完成某些事情。

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-09-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-07
          • 2018-10-22
          相关资源
          最近更新 更多