C#如何实现可存储继承自同一抽象类对象的列表并解决转换报错
报错原因
C# 中的List<T>属于**不变(Invariant)**泛型类型,不支持协变转换,即便A是C的子类,List<A>和List<C>也完全是两种没有继承关系的类型,无法直接互相转换。编译器阻止该操作是为了保证类型安全:如果允许List<A>转为List<C>,你完全可以在Method里往列表插入一个B类型的实例,破坏原List<A>的类型约束,这就是CS1503报错的根本原因。
解决方案
根据你的使用场景可以选择以下三种方案:
方案1:仅需读取列表元素、修改元素本身属性(不需要增删列表元素)
使用支持协变的泛型接口IEnumerable<C>作为方法参数即可,调用代码无需修改:public class D { public void Method(IEnumerable<C> list) { // 可以正常修改继承自C的x、y、z属性 foreach (var item in list) { item.x = 1; item.y = 2; item.z = 3; } } }方案2:需要修改列表结构(增/删元素),同一个D实例仅存储同一子类类型的列表
将D声明为带约束的泛型类即可:// 约束泛型T必须继承自C public class D<T> where T : C { public List<T> list { get; set; } public void Method(List<T> list) { // 支持所有列表操作:增删元素、修改元素属性 list.Add(default(T)); list[0].x = 10; } }调用示例:
// 存储A类型的列表 D<A> dA = new D<A>(); dA.list = new List<A>(); dA.Method(new List<A>()); // 存储B类型的列表 D<B> dB = new D<B>(); dB.list = new List<B>(); dB.Method(new List<B>());方案3:需要同一个D实例可切换存储
List<A>或List<B>
将列表属性/参数声明为IList<C>,调用时做类型转换即可:public class D { public IList<C> list { get; set; } public void Method(IList<C> list) { // 支持所有列表操作 } }调用示例:
List<A> list = new List<A>(); D d = new D(); // 转换为IList<C>后传入 d.Method(list.Cast<C>().ToList()); d.list = new List<B>().Cast<C>().ToList();注意:该方案得到的
IList<C>是新生成的列表,对它的增删操作不会同步到原List<A>/List<B>,如果需要同步原列表可以自行封装适配逻辑。
内容的提问来源于stack exchange,提问作者Jan
相关产品推荐
相关产品推荐

