C#中如何确保泛型类型为类的基类?解决动物分组问题
问题:C#实现动物实例安全加入对应组的类型约束
原始代码
用户的初始代码结构如下,需要解决泛型类型占位符???的类型安全问题:
public abstract class Animal { protected List<List<???>> _groups; public Animal(List<List<???>> groups) { _groups = groups; foreach (List<???> group in groups) { group.Add(this); } } } public abstract class Mammal : Animal { public Mammal(List<List<???>> groups) : base(groups) { } } public class Dog : Mammal { public Dog(List<List<???>> groups) : base(groups) { } }
需求说明
创建动物实例时,需要传入其所属的所有组(比如List<Mammal>或List<Animal>),要求:
- 动物只能加入类型兼容的组(例如
Dog可以加入Mammal或Animal组,但不能加入Duck组) - 动物能同时加入所有符合类型要求的组
用户尝试过的泛型约束写法在C#中不被支持:
public class Dog : Mammal { public Dog(List<List<T>> groups) : base(groups) where Dog : T { } }
解决方案:通过类型检查实现类型安全
不需要复杂的泛型类,直接在基类构造函数中验证组的元素类型是否兼容当前实例类型,即可实现需求:
public abstract class Animal { protected List<IList> _groups = new List<IList>(); public Animal(params IList[] groups) { foreach (var group in groups) { // 获取组的泛型元素类型 var elementType = group.GetType().GetGenericArguments()[0]; // 验证当前实例是否可以被该组容纳(元素类型是当前类的基类或自身) if (elementType.IsAssignableFrom(GetType())) { group.Add(this); _groups.Add(group); } else { throw new ArgumentException($"无法将{GetType().Name}加入类型为{elementType.Name}的组"); } } } // 从所有组中移除当前动物的方法 public void Kill() { foreach (var group in _groups) { group.Remove(this); } } } public abstract class Mammal : Animal { public Mammal(params IList[] groups) : base(groups) { } } public class Dog : Mammal { public Dog(params IList[] groups) : base(groups) { } } public class Duck : Animal { public Duck(params IList[] groups) : base(groups) { } }
使用示例
// 定义不同类型的组 var mammalGroup = new List<Mammal>(); var animalGroup = new List<Animal>(); var duckGroup = new List<Duck>(); // 正确:Dog可以加入Mammal和Animal组 var dog = new Dog(mammalGroup, animalGroup); // 错误:尝试将Dog加入Duck组会抛出ArgumentException // var invalidDog = new Dog(duckGroup); // 正确:Duck可以加入Animal组 var duck = new Duck(animalGroup); // 错误:尝试将Duck加入Mammal组会抛出ArgumentException // var invalidDuck = new Duck(mammalGroup);
方案优势
- 无需修改原有类的继承结构,仅在基类构造函数中添加类型检查
- 自动验证组的兼容性,避免错误的类型加入
- 支持任意层级的继承关系(如
Dog→Mammal→Animal) - 保留了
Kill方法从所有组中移除实例的功能
内容的提问来源于stack exchange,提问作者Anitoni
相关产品推荐
相关产品推荐

