从C#中的单个方法返回多个类型

时间:2013-06-23 19:35:42

标签: c# inheritance casting return-value

我正在研究Xna / C#中的基本游戏和2D引擎,我正在尝试简化其中的一些内容。我有一个来自引擎的Entity2D基类和两个特定于游戏的类继承它:Tower和Enemy。在我的引擎中,而不是有两个单独的列表,一个用于Towers,一个用于Enemies,我想将它们组合成一个通用列表。然后,我有问题,当我需要从列表中返回一个塔或从列表中返回一个敌人。我知道我可以使用引擎对象中的类型转换:

class Entity2D {...} //engine object
class Tower : Entity2D {...} //game specific
class Enemy : Entity2D {...} //game specific

//In engine:
public Entity2D GetEntity(int index) { ...return objects[index];}

//Somewhere in the game
{
    Enemy e = GetEntity(0) as Enemy;
    if(e != null)
        //Enemy returned

    Tower t = GetEntity(0) as Tower;
    if(t != null)
        //Tower returned
}

当然这似乎效率很低。

我还调查了一下is关键字,看起来效果如下:

Entity2D entity = GetEntity(0);
if(entity is Tower)
{
    Tower t = (Tower)entity;
    t.DoTowerThings();
}

仍然会导致返回一个基础对象并使用更多内存来创建第二个对象并对其进行类型转换。

真正好的是,如果有办法做这样的事情:

//In engine:
public T GetEntity(int index) 
{ 
    if(T == Tower) //or however this would work: (T is Tower), (T as Tower), etc
        return objects[index] as Tower;
    else if(T == Enemy) 
        return objects[index] as Enemy;
    else return null;
}

Enemy e = GetEntity(0);

但是那会破坏引擎和游戏分离的引擎部分

我正在寻找最清晰,最节省内存的方法,同时仍然让Entity2D成为引擎,并避免在引擎中使用Tower或Enemy。

欢迎任何建议!

谢谢!

3 个答案:

答案 0 :(得分:1)

几乎就在那里!

//In engine:
public T GetEntity<T>(int index) where T : Entity2D
{ 
    return objects[index] as T;
}
//Somewhere else:
Enemy e = GetEntity<Enemy>(0);

注意:如果objects[index]不是T,则会返回null

但是,如果是我的游戏,我会为每种类型的对象保留单独的列表。

答案 1 :(得分:0)

你可以这样做,(full code on Github

public T GetEntity<T>(int index) where T : Entity2D
{
    return list.ElementAt(index) as T;
}

如果元素不是预期的类型,它将返回null。

Tower t = GetEntity<Tower>(0);

答案 2 :(得分:0)

如果你必须消除返回值的歧义,那么代码的结构很糟糕,对象在逻辑上并不相似,你最好有两个列表,每个类型有一个单独的访问器。

但是,如果类型非常相似,并且您只需要很少消除歧义,那么请执行以下操作: -

abstract class GameEntity : Entity2D
{
  abstract public void TowerOnlyFunction (args); // need to look up exact syntax, but you get the idea
  abstract public void EnemyOnlyFunction (args);

  void CommonFunctions (args);
}

class Tower : GameEntity
{
  public void TowerOnlyFunction (args)
  {
    // code
  }
  public void EnemyOnlyFunction (args)
  {
    // empty
  }
}

class Enemy : GameEntity
{
  public void TowerOnlyFunction (args)
  {
    // empty
  }
  public void EnemyOnlyFunction (args)
  {
    // code
  }
}

//Somewhere in the game
void DoSomethingWithTower ()
{
  GameEntity e = GetEntity(0);
  e.TowerOnlyFunction ();
}