我可能错误地标题了标题,但基本上我想要做的是有一个相同对象的列表,其中包含不同的泛型类型。
就是这样的例子,我有一个使用基于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),以确保我不会把它搞砸到某个地方。
答案 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>
{ }