【发布时间】:2011-03-21 17:59:09
【问题描述】:
这篇文章包含很多代码,但如果你能阅读并理解它,我将不胜感激......并希望提出解决方案
假设我正在构建一个网络游戏,其中需要绘制实体并相应地从服务器更新其中一些实体。
Drawable 类负责在屏幕上绘制实体:
class Drawable
{
public int ID { get; set; } // I put the ID here instead of having another
// class that Drawable derives from, as to not
// further complicate the example code.
public void Draw() { }
}
从服务器接收的数据实现IData,每个具体的IData 具有不同的属性。假设我们有以下数据,Player 和 Enemy 将收到:
interface IData
{
int ID { get; set; }
}
class PlayerData : IData
{
public int ID { get; set; }
public string Name { get; set; }
}
class EnemyData : IData
{
public int ID { get; set; }
public int Damage { get; set; }
}
应该可以从服务器更新的游戏实体实现IUpdateable<T>,其中T 是IData:
interface IUpdateable<T> where T : IData
{
void Update(T data);
}
因此,我们的实体是Drawable 和Updateable:
class Enemy : Drawable, IUpdateable<EnemyData>
{
public void Update(EnemyData data) { }
}
class Player : Drawable, IUpdateable<PlayerData>
{
public void Update(PlayerData data) {}
}
这就是游戏的基本结构。
现在,我需要存储这些Drawable 和Updateable 对象中的Dictionary,存储Drawable 的ID 作为键和一个包含Drawable 和Updateable 对象的复杂对象和他们的远程混凝土IData:
class DataHolder<T, T1> where T:Drawable, IUpdateable<T1> where T1:IData
{
public T Entity{ get; set;}
public IData Data{ get; set;}
public DataHolder(T entity, IData data)
{
Entity = entity;
Data = data;
}
}
例如,假设我目前有以下实体:
var p1 = new Player();
var p1Data = new PlayerData();
var e1 = new Enemy();
var e1Data = new EnemyData();
var playerData = new DataHolder<Player, PlayerData>(p1, p1Data);
var enemyData = new DataHolder<Enemy, EnemyData>(e1, e1Data);
我现在需要一个 Dictionary 来保存实体的 ID 作为键(p1.ID 和 e1.ID)及其 DataHolder(playerData 和 enemyData)及其值。
类似于以下内容(下面的代码只是显示了我想要做的事情,因此它不会编译):
Dictionary<int, DataHolder> list = new Dictionary<int, DataHolder>();
list.Add(p1.ID, playerData);
list.Add(e1.ID, enemyData);
如何构建这样的字典?
[更新]
关于使用,我需要能够做到以下几点:
foreach (var value in list.Values)
{
var entity = value.Entity;
entity.Update(value.Data);
}
我也尝试过将DataHolder的设计改成如下:
class DataHolder<T> where T:Drawable, IUpdateable<IData>
{
public T Entity{ get; set;}
public IData Data{ get; set;}
public DataHolder(T entity, IData data)
{
Entity = entity;
Data = data;
}
}
然后我尝试了类似以下的方法:
var playerData = new DataHolder<Player>(p1, p1Data); //error
但这会引发编译时错误:
“玩家”类型必须是可转换的 到 'IUpdateable
' 按顺序 将其用作参数 'T' 泛型类'DataHolder '
这是出于什么原因抛出的? Player 实现 IUpdateable<PlayerData> 和 PlayerData 实现 IData。这是方差的问题吗?有什么办法可以解决吗?
【问题讨论】:
-
通过查看此处的答案,我认为您可能只用几行文本而无需或很少的代码就可以提出这个问题。基本上你要问的是如何构造一个映射到泛型类型的字典,然后能够将该泛型类型的不同实现放入同一个字典中。对吗?
-
是的,但我想让我的意图非常清楚,以免被误解,这会导致在问题中添加更新,以澄清我真正想要的 :-)
标签: c# generics collections interface covariance