C#泛型列表有很多种类

时间:2014-12-21 13:34:22

标签: c# generics

我可能错误地标题了标题,但基本上我想要做的是有一个相同对象的列表,其中包含不同的泛型类型。

就是这样的例子,我有一个使用基于Tile的地图的Tower Defense游戏。所以我有图层(图块层,对象图层,ai图层)。所以我有这个课程:

 public class Layer<T>{

    // The name of the layer
    private String name;

    // All the cells in this layer
    private Cell<T>[] cells; 

    public Layer(Map map, String name){
        cells = new Cell<T>[map.Width * map.Height];
        this.name = name;
        CreateCells();
    }

    /// <summary>
    /// Fills the array of cells with blank, unoccupied cells
    /// </summary>
    private void CreateCells(){
        var index = 0;
        for (var x = 0; x < cells.Length; x++){
            for (var y = 0; y < cells.Length; y++){
                cells[index] = new Cell<T>(x, y);
                index++;
            }
        }
    }

    // Gets the array of cells in this layer
    public Cell<T>[] GetCells(){
        return cells;
    }

    /// <summary>
    /// Gets a cell at a specific index/coordinate
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns>The cell at the X and Y coordinate/index</returns>
    public Cell<T> GetCellAt(int x, int y){
        foreach (var c in cells){
            if (c.GetX() != x || c.GetY() != y) continue;
            return c;
        }
        throw new Exception("Cell not found at " + x+"x"+y);
    }

    /// <summary>
    /// Gets the name of this layer
    /// </summary>
    /// <returns></returns>
    public String GetName(){
        return name;
    }

}

现在这很好,这意味着我可以指定一个包含一种对象的图层。在图块层中,我想要可以容纳图块的单元格,我想要图层保存对象的对象等等。

问题是,当我尝试在我的地图类中创建图层列表时。我不太确定所谓的#34;通配符&#34;在java(?)中输入类似的东西。

我试过这个,没有成功:

      private List<Layer<dynamic>> layers; 

当我这样做时,它吓坏了:

            layers = new List<Layer<dynamic>>();
        layers.Add(new Layer<Tile>(this, "tiles"));

所以我显然使用了不正确的语法。

在这种情况下我该怎么做?

更新1:

根据人们的建议,我尝试在图层内部使用常用方法的接口(获取单元格,不是什么)。这种设计的问题是该层需要类型T才能确定每个单元可以使用的对象类型。

更新2:

我无法想办法以任何其他方式做到这一点,所以我决定采用这个解决方案:

一起删除泛型(差不多)而不是为占用者提供单元格类型T,我给它了GameObject类型。现在大多数事情都继承自游戏对象(塔,瓦片,障碍物,粒子),但是AI相关的代码都没有,所以我不得不改变我的路径查找代码。

我现在有以下内容:

   public class Layer{

    // The name of the layer
    private String name;

    // All the cells in this layer
    private Cell[] cells; 

}

Generics也已从Cell类中删除:

    public class Cell{

    // The object inside this cell
    private GameObject occupant; // Note the new occupant type
    // The width and height of the cell in world coordinates
    public const float WIDTH = 1, HEIGHT = 1;
    // The coordinate of this cell
    private int x, y;
}

现在我在Cell类中使用泛型方法,如下所示:

        /// <summary>
    /// Gets the occupant in this cell
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T GetOccupant<T>() where T : GameObject{
        return occupant as T;
    }

所以这里的代码按预期工作:

            layers = new List<Layer>();
        layers.Add(new Layer(this, "tiles"));
        GetLayer("tiles").GetCellAt(5, 5).SetOccupant(new EnemyScientist(null, 5, 1, 6));
        Enemy e = GetLayer("tiles").GetCellAt(5, 5).GetOccupant<Enemy>();

虽然不是最好看的代码,但地图系统只会用于这个游戏,所以我并不特别担心编写可重复使用的代码,主要是功能代码。忽略这样一个事实,即我刚刚将一个敌人卡在了瓷砖图层中,但我会添加一些便宜的支票(typeof),以确保我不会把它搞砸到某个地方。

2 个答案:

答案 0 :(得分:3)

问题在于,Layer<Tile>Layer<Ai>没有任何共同的父类,您可以将它们都投射到。最接近的是所有引用类型都继承的非常通用的object

正如Lasse建议的那样,在这种情况下,常见的方法是定义一个他们都继承的通用接口:

interface ILayer 
{
    void CreateCells();
}

public class Layer<T> : ILayer 
{

然后您的地图可以List ILayer s:

layers = new List<ILayer>();
layers.Add(new Layer<Tile>(this, "Tiles"));

您需要考虑一种设计ILayer界面的方法,使其不依赖于通用参数T

答案 1 :(得分:0)

在.NET Framework库中,它实现如下:

class Program
{
    static void Main(string[] args)
    {
        var layers = new List<ILayer<object>>();
        layers.Add(new Layer<string>()); // It is covariance so we can only use reference types.
    }
}

public interface ILayer<out T>
{
    void CreateCells();
    ICell<T>[] GetCells();
}

public class Layer<T> : ILayer<T>
{ }

public interface ICell<out T>
{ }

public class Cell<T> : ICell<T>
{ }