2012-09-18 58 views
3

我有類是關鍵字不具有繼承工作(基類是DerivedObject)=真正的「我怎樣才能避免」

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而不是汽車。我現在可以調用ToString()方法,然後做一個正則表達式,但如果我重命名我的類,我會打破我的代碼...

換句話說,如果我通過的車輛不能跨越,它恰好是汽車或SpeedCar我將進入一個無限循環......

回答

8

我怎麼能檢查車輛是SpeedCar但不是汽車

vehicle.GetType() == typeof(SpeedCar) 
+0

非常感謝!!!! –

+1

@TonoNam:不客氣。順便說一句,你真的不應該隱藏繼承成員'CanCross'。使其成爲'virtual'並使用'override'關鍵字覆蓋後代類的行爲。另外,爲了拋棄醜陋的類型檢查,你可以添加一個虛擬屬性'Car.ReplaceWithCar'。 – Dennis

+0

然後你的方法'Foo'看起來像這樣:'if(!car.CanCross(obstacle)){return car.ReplaceWithCar!= null? Foo(car.ReplaceWithCar):null; }' – Dennis

-1

你應該只檢查(車輛賽車)

10

您可以使用is運算符來執行此操作 - 事實上,它比使用GetType()要快一些。

你的繼承層次是IVehicle - >Car - >RaceCar,所以任何這是一個RaceCar也將是一個CarIVehicle。如果你第一次測試基類,你的代碼將永遠不會達到更具體的測試,因爲基類將無論如何匹配 - 這就是爲什麼你有它的問題。

在需要爲繼承鏈中的類做不同事情的情況下測試的正確方法是首先測試更具體的(更多派生的)類,然後測試基類。

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

Dennis' answer是正確的,使用虛擬函數簡化了這些情況,因爲你能避免這幾樣在大多數情況下測試時,你有虛函數 - 簡單地所有派生類可以提供自己的實現函數(或依賴在適當的情況下不會覆蓋它的基本實現)。如果基礎實現沒有意義,則可以使用關鍵字abstract指示派生類必須提供實現而不依賴於基類。那些派生類然後使用override來實現這樣的抽象函數。

5

雖然其他人已經回答了您的問題,但我想爲您提供另一種生成Foos的方法。 使用Polymorphism擺脫無休止的if-else鏈(或switch語句),並讓車輛實現方法CreateAlternateVehicle

public interface IVehicle 
{ 
    bool CanCross(string obstacle); 

    IVehicle CreateAlternativeVehicle(); 
} 

一個Car將創建一個RaceCar,一個RaceCarOldCar等。鏈中的最後一輛車可能會返回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); 
    } 
    ... 
} 

很多時候,如果其他鏈和switch語句是一種提示,一些可能是以更加面向對象的方式完成。

相關問題