c# - C#中涉及集合、泛型和接口(interface)的设计问题

标签 c# generics collections interface covariance

这篇文章包含很多代码,但如果您能花一些时间阅读和理解它,我将非常感激......并希望能找到一个解决方案

假设我正在构建一个网络游戏,其中需要绘制实体,并相应地从服务器更新其中一些实体。

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持有不同的属性(property)。假设我们有以下数据 PlayerEnemy将收到:

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>哪里TIData :

interface IUpdateable<T> where T : IData
{
    void Update(T data);
}

我们的实体是 DrawableUpdateable :

class Enemy : Drawable, IUpdateable<EnemyData>
{
    public void Update(EnemyData data) { }
}

class Player : Drawable, IUpdateable<PlayerData>
{
    public void Update(PlayerData data) {}
}

这就是游戏的基本结构。


现在,我需要存储 Dictionary其中DrawableUpdateable对象,存储 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.IDe1.ID )及其 DataHolder ( playerDataenemyData )及其值。

类似于以下内容(下面的代码仅显示了我想要执行的操作,因此它不会编译):

 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

但这会引发编译时错误:

The type 'Player' must be convertible to 'IUpdateable<IData>' in order to use it as parameter 'T' in the generic class 'DataHolder<T>'

这个抛出的原因是什么? Player实现IUpdateable<PlayerData>PlayerData实现IData 。这是方差问题吗?有什么办法可以解决这个问题吗?

最佳答案

使您的 DataHolder 类实现或继承非泛型类或接口(interface),然后创建该(非泛型)类型的字典。

关于c# - C#中涉及集合、泛型和接口(interface)的设计问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3346263/

相关文章:

c# - 过早中止 BeginRead 和 BeginWrite 的正确方法?

c# - TimeoutException、TaskCanceledException C#

scala - scala 中的循环类型参数定义

java - java中空间和时间复杂度较低的panagram

java - 如何在velocity模板中使用java方法获取列表

c# - 从 C# 调用 C dll 代码?

c# - 成功链接帐户后,Google 操作不提供 user.profile.payload 对象

java - 类型安全、Java 泛型和查询

Java泛型方法类型参数

oracle - 从 Oracle Cursor 批量收集列的子集