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

車両が障害物を越えることができない場合は、別の車両で試すために同じメソッドを再帰的に再度呼び出すことに注意してください。私の質問は、なぜ車両= SpeedCarの場合、if (vehicle is Car)と評価されるのですか?おそらくそれを継承しているからでしょう。車両がSpeedCarであるが、Carではないかどうかを確認するにはどうすればよいですか。これで、ToString()メソッドを呼び出して正規表現を実行できますが、クラスの名前を変更すると、コードが壊れます...

言い換えれば、私が通過する車両が横断できず、それがたまたま車またはスピードカーである場合、私は無限ループに入ります...

4

4 に答える 4

16

演算子を使用してこれを行うことができますis- 実際、使用するよりも多少高速ですGetType()

継承階層はIVehicle-> Car->RaceCarであるため、 a であるものRaceCarはすべて 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 であるが Car ではないかどうかを確認するにはどうすればよいですか

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

aは a 、 a anなどCarを作成します。チェーンの最後の車が戻る可能性があります。例として、クラスは次のように実装します。RaceCarRaceCarOldCarnullCar

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 に答える