2013-12-19 71 views
6

我有一個基類名爲CollidableObject和一個名爲PlayerEnemyInertObject夫婦繼承類等迭代通過基類的所有實例和繼承的類

我試圖找到一個簡單的方法來遍歷通過它們的所有實例,所以我最初創建了一個類型爲CollidableObject的列表,並將所有繼承類的實例放在那裏。

的事情是,由於多態的性質,當我做了以下

foreach (CollidableObject CollidableObject in collidableObjects) 
{ 
    if (CollidableObject is Player) 
    { 
    CollidableObject.Draw(spriteBatch, testPlayerTexture); 
    } 
    // Then the same prodedure for each type of CollidableObject. 
    // Might change to switch or something.        
} 

它調用從CollidbaleObject基地,而不是從覆蓋/新通用Draw方法抽籤方法Player/Enemy/inertObject類。

我該如何解決這個問題。有沒有辦法從同一棵樹中迭代對象集合,但保持它們的繼承類型?

+2

我意識到這是輔助性的,但如果您必須爲每種子類型提供不同的參數方法,那麼這種方法就會失敗。無論如何,請查看關於覆蓋方法的文章;你應該有一個虛擬的方法,並使用覆蓋關鍵字來覆蓋它:http://msdn.microsoft.com/en-us/library/ebca9ah3.aspx – Casey

+1

*「不是覆蓋/從播放器/敵人/惰性對象新的類。「* - 哪一個,重寫或新? – Harrison

回答

9

是否沒有辦法通過同一棵樹中的對象集合進行迭代,但保持它們的繼承類型?

當然,有辦法做到這一點。但是,你需要設置你的層次結構以適當的方式:

  • Draw方法在CollidableObject需要被打上virtual
  • Player需要Draw方法被標記爲override

這將確保來自您帖子的呼叫將被路由到Player的方法覆蓋,而不是基地的方法。

在相關說明中,當您看到使用is運算符檢查對象的動態類型的代碼時(如在if (CollidableObject is Player)中),您應該強烈懷疑您正在做錯某些事情。例如,您可能會錯過double dispatch

如果您只需要知道類型的正確紋理,則可以將紋理置於Dictionary<Type,Texture> textureForType中,並使用可碰撞對象的GetType()將正確的紋理拖動到循環中。

+1

謝謝!關於「is」運算符的事情,爲什麼在這種情況下會出錯? – user3120072

+1

@ user3120072儘管使用'is'並不會自動錯誤,它通常用於替代更好的選擇。例如,不是檢查對象的動態類型,而是可以調用另一個虛擬方法來爲您提供紋理。使用'if(x是TypeXyz)'調度鏈的危險是,當你添加一個新類型時,你必須找到每個你有'if(x is ...)'鏈的地方,然後添加處理那裏有新的類型。在某些情況下,這只是很多工作,但在其他情況下(當您編寫庫時),這根本不可能。 – dasblinkenlight

4

你試過:

foreach (CollidableObject CollidableObject in collidableObjects) 
{ 
    if (CollidableObject is Player) 
    { 
     ((Player) CollidableObject).Draw(spriteBatch, testPlayerTexture); 
    }  
    //Then the same prodedure for each type of CollidableObject. Might change to switch or something.        
} 
+0

這工作,但我會失去這種方法的信息? – user3120072

+0

@ user3120072 - 不清楚你擔心什麼「信息」?如果你認爲'(Player)'cast會創建新的對象而不是你的假設是錯誤的 - cast不會創建新的對象,而是強制引用對象爲不同的類型(也會有運行時檢查以確保可以投射) 。 –

-1

我會每個類實現Draw方法是特定於類。他們都需要相同的簽名。

那麼你的foreach並不關心哪一個階級它實際上是,和看起來像這樣

foreach (CollidableObject CollidableObject in collidableObjects) 
{ 
     CollidableObject.Draw(....);           
} 

這將是這樣做的「面向對象」的方式。

+2

這就是OP已經在做的事情,但他們可能沒有正確使用虛擬/覆蓋,正如@dasblinkenlight的回答中所述 – Scampbell