C#具有多种类型的通用列表

C#具有多种类型的通用列表,c#,generics,C#,Generics,我可能对标题的措词不正确,但基本上我想做的是有一个相同对象的列表,其中包含不同的泛型类型 举个例子,我有一个塔防游戏,它使用基于瓷砖的地图。所以我有层(瓷砖层,对象层,ai层)。所以我有一节课: public class Layer<T>{ // The name of the layer private String name; // All the cells in this layer private Cell<T>[] cel

我可能对标题的措词不正确,但基本上我想做的是有一个相同对象的列表,其中包含不同的泛型类型

举个例子,我有一个塔防游戏,它使用基于瓷砖的地图。所以我有层(瓷砖层,对象层,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;
    }

}
泛型也已从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;
    }
//
///获取此单元格中的占用者
/// 
/// 
/// 
public T getOccount(),其中T:GameObject{
返回居住者为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>();
layers=newlist();
层。添加(新层(本“瓷砖”);
GetLayer(“tiles”).GetCellAt(5,5).SetOccuperator(新敌人科学家(null,5,1,6));
敌人e=GetLayer(“tiles”).GetCellAt(5,5).GetOccuptain();

虽然不是最好看的代码,地图系统将只用于这个游戏,所以我并不特别担心编写可重用的代码,大部分是功能代码。忽略一个事实,我刚刚在平铺层中插入了一个敌人,但我将添加一些廉价的检查(typeof),以确保我不会在某个地方把它搞砸。

问题是
层和
层没有任何可以将两者都强制转换的父类。最接近的是所有引用类型继承自的非常通用的
对象

在这种情况下,一种常见的方法是,正如Lasse所建议的,定义一个它们都从中继承的公共接口:

interface ILayer 
{
    void CreateCells();
}

public class Layer<T> : ILayer 
{

您需要考虑一种方法来设计
ILayer
接口,使其不依赖于.NET Framework库中的泛型参数
T

,实现方式如下:

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>
{ }
类程序
{
静态void Main(字符串[]参数)
{
var layers=新列表();
layers.Add(new Layer());//它是协方差,所以我们只能使用引用类型。
}
}
公共接口ILayer
{
void CreateCells();
ICell[]GetCells();
}
公共类层:ILayer
{ }
公共接口ICell
{ }
公共类单元格:ICell
{ }

新列表
可能吗?此外,C#还有通用约束—在文档中查找
where
。您是否考虑过使用公共位实现接口?然后列表可以是
ListI可以删除层的泛型类型,而改为层继承和接口是的,考虑到每个层都有相同的字段,这实际上可能是一个不错的选择。我将研究@LasseV.Karlsen建议的内容。您打算如何处理层列表?如果您正在对它们进行迭代,或者要应用一些常见的操作,那么似乎会有一些常见的行为,这是接口的理想候选者。最好先在静态类型语言中查找此类定义,否则您可能会发现您将要处理大量后续的强制转换。@Chris my layers将用于获取给定层上单元格中的任何内容。因此,如果你可以想象我想放置一座塔,首先我们抓取对象层,确保一座塔不存在,如果不存在,我们检查瓷砖层,确保“地形”可以容纳一座塔,如果是这样的话,请放置它,然后我们检查AI层,找出哪些实体在使用该磁贴进行导航时使用AI层并调整路径。谢谢,这看起来越来越像问题的最可能解决方案。请阅读您的编辑,有一个问题,该层需要类型T来确定每个单元格可以容纳的类型。因此,接口可能无法实际工作here@GibboLayer类仍然可以有一个泛型类型
T
(请参见我使用的
public class Layer:Layer{
)。简单地说,您的map类需要不知道
T
w.r.T。它是如何存储和与层交互的。(例如,您可能需要让
单元格
单元格
继承,这样您的
GetCells()
就可以返回
列表
,而不是
列表
)。很抱歉,我刚刚重新阅读了您的帖子,由于调用层的类和调用的接口,我搞混了LAyer@Gibbo不用担心现在,我已将接口重命名为
ILayer
,以符合.NET命名约定。这将进行编译,但我不确定它最终是否会提供任何好处,并且它为运行时异常打开了可能性,否则不会发生。例如:
var layers=new List;layers.Add(new Layer());ICell[]arr=layers[0].GetCells();arr[0]=new Cell();//runtine exception
out
不应被用作让编译器忽略类型安全性的方法。是的,对象的框在被分配后不能更改为其他类型。表示这是正常的:ICell Cell=new Cell();
            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>();
interface ILayer 
{
    void CreateCells();
}

public class Layer<T> : ILayer 
{
layers = new List<ILayer>();
layers.Add(new Layer<Tile>(this, "Tiles"));
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>
{ }