如何将泛型基类Equipment<T>的不同子类存入同一列表?
这个问题其实是C#泛型不变性导致的——默认情况下,泛型类不会因为类型参数的继承关系而产生子类关系。哪怕WeaponData继承自EquipmentData,Equipment<WeaponData>也不会被看作Equipment<EquipmentData>的子类,所以直接用List<Equipment<EquipmentData>>肯定加不进去Weapon或者Shield对象。
给你两个最实用的解决方案,根据你的业务场景选:
方案1:定义非泛型基接口/基类
这是最通用的方案,不管你的泛型类有没有输入输出限制都能用。我们先搞一个不带泛型的基接口,让所有泛型Equipment<T>都实现它:
// 非泛型接口,定义所有装备共有的行为/属性 public interface IEquipment { // 比如所有装备都有基础数据,这里用基类类型暴露 EquipmentData BaseData { get; } void Use(); // 假设所有装备都有使用方法 } // 泛型基类实现这个接口 public abstract class Equipment<T> : IEquipment where T : EquipmentData { public T Data { get; protected set; } // 显式实现接口,把泛型Data转成基类类型 EquipmentData IEquipment.BaseData => Data; // 实现通用方法,也可以留抽象让子类实现 public abstract void Use(); } // 你的子类不需要改,继续正常继承 public class Weapon : Equipment<WeaponData> { public override void Use() { // 武器的使用逻辑 } } public class Shield : Equipment<ShieldData> { public override void Use() { // 盾牌的使用逻辑 } }
然后你的列表就可以写成:
List<IEquipment> equipmentInventory = new List<IEquipment>(); equipmentInventory.Add(new Weapon()); equipmentInventory.Add(new Shield());
这样既保证了类型安全,又能统一操作所有装备(比如调用Use()方法,或者访问BaseData)。
方案2:利用泛型接口的协变性
如果你的Equipment<T>主要是输出数据(比如只暴露T类型的属性,没有接收T作为参数的方法),那可以用C#的协变接口。协变允许我们把IEquipment<WeaponData>隐式转换成IEquipment<EquipmentData>,因为WeaponData是EquipmentData的子类。
代码示例:
// 用out关键字标记协变类型参数T,T只能作为返回值 public interface IEquipment<out T> where T : EquipmentData { T Data { get; } // 注意:不能有这样的方法:void SetData(T data); 因为T作为输入的话协变不允许 } public abstract class Equipment<T> : IEquipment<T> where T : EquipmentData { public T Data { get; protected set; } }
这时候列表就可以这么定义:
List<IEquipment<EquipmentData>> equipmentList = new List<IEquipment<EquipmentData>>(); equipmentList.Add(new Weapon()); // 现在可以正常添加了! equipmentList.Add(new Shield());
但要记住协变的限制:接口里的T只能出现在返回值的位置,不能作为方法的参数类型。如果你的装备类需要设置T类型的数据(比如SetData(T data)),那这个方案就不适用,得用方案1。
不推荐的方案:用List
相关产品推荐
相关产品推荐

