含泛型属性的类必须为泛型类?泛型类使用编译问题咨询
解决泛型Foo在非泛型Bar中的使用问题
这个场景我之前也碰到过——不想把Bar改成泛型类,但又要持有不同类型参数的Foo<T>实例列表。下面是几种靠谱的解决方案,你可以根据实际需求选:
1. 给Foo定义非泛型基类/接口(最推荐)
这是类型最安全、扩展性最好的做法。先抽一个非泛型的基类或接口,让所有Foo<T>都继承它,这样Bar就能用这个基类来声明列表:
// 定义非泛型基类,放所有Foo<T>共有的逻辑 public abstract class FooBase { // 比如统一获取列表元素数量的方法 public abstract int GetItemCount(); } // 泛型Foo<T>继承基类 public class Foo<T> : FooBase { public List<T> FooList { get; set; } = new List<T>(); public override int GetItemCount() => FooList.Count; } // 现在Bar可以直接用List<FooBase>了 public class Bar { public List<FooBase> Foos { get; set; } = new List<FooBase>(); }
适用场景:你需要在Bar中统一操作所有Foo实例,比如统计元素数量、执行通用逻辑。
注意:如果要访问具体Foo<T>的FooList元素,需要做类型转换(比如(Foo<int>)fooBase)。
2. 使用object作为Foo的类型实参(最简单)
如果Bar只是单纯持有Foo实例,不需要操作FooList里的具体元素,可以直接用Foo<object>:
public class Bar { public List<Foo<object>> Foos { get; set; } = new List<Foo<object>>(); }
优点:零额外代码,直接能用。
缺点:类型不安全——存入Foo<int>时需要强制转成Foo<object>,取出时再转回来,容易出运行时错误。
3. 利用泛型协变(只读场景适用)
如果FooList是只读的,可以定义一个协变接口,这样不同类型的Foo<T>能自动兼容到IFoo<object>:
// 协变接口,out关键字表示T是协变类型 public interface IFoo<out T> { // 只能用只读的IEnumerable,不能用List(因为List是读写的,不支持协变) IEnumerable<T> Items { get; } } public class Foo<T> : IFoo<T> { public List<T> FooList { get; set; } = new List<T>(); // 显式实现接口,返回只读的集合 IEnumerable<T> IFoo<T>.Items => FooList; } // Bar里用List<IFoo<object>>,就能存Foo<int>、Foo<string>等实例 public class Bar { public List<IFoo<object>> Foos { get; set; } = new List<IFoo<object>>(); }
适用场景:你只需要读取FooList的元素,不需要修改它。
优势:既保持类型安全,又能容纳不同类型的Foo<T>。
4. 使用dynamic类型(不推荐,应急用)
如果是临时测试或者完全不需要编译时类型检查,可以用dynamic:
public class Bar { public List<dynamic> Foos { get; set; } = new List<dynamic>(); }
优点:任何Foo<T>都能直接塞进去,不用转换。
缺点:编译时不会检查类型错误,所有问题都要到运行时才暴露,调试起来头疼,除非万不得已别用。
内容的提问来源于stack exchange,提问作者João Menighin
相关产品推荐
相关产品推荐

