2013-12-19 43 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