C#中List<Parent>存储子类元素时如何保留子类属性?
问题原因与解决方案
一、问题本质
你遇到的核心问题是编译时类型与运行时类型的差异:
Start.list的类型是List<Base>,所以从集合中取出的元素,编译时被编译器识别为Base类型。而Base类并没有定义b或c成员,直接访问s.list[0].b会触发编译报错。- 你提到的
List<Object>例子能正常运行,是因为Console.WriteLine会调用对象的ToString()方法——Object是所有类型的基类,任何对象都能隐式转换为Object,且运行时会调用实际类型的ToString()实现,不需要直接访问专属成员,因此不会有编译问题。
二、针对性解决方案
结合你要求「list仅存储B或C的实例(不同时存两种)、尽量不用泛型」的需求,提供三种可行方案:
方案1:显式类型转换(快速解决访问问题)
取出元素时,先将其强转为对应的子类类型,再访问专属成员。为避免类型转换失败报错,建议先做类型判断:
Start s = new Start(); B b = new B(1, 2); s.list.Add(b); // 安全类型转换+访问 if (s.list[0] is B bInstance) { Console.WriteLine(bInstance.b); // 正常输出2 }
方案2:给Start类添加类型约束逻辑(确保集合类型单一)
通过封装Add方法,限制集合只能添加同一种类型的实例,避免混合存储B和C:
class Start { public List<Base> list { get; private set; } private Type _allowedType; public Start() { list = new List<Base>(); } // 对外暴露的添加方法,做类型校验 public void Add(Base item) { if (_allowedType == null) { _allowedType = item.GetType(); list.Add(item); } else if (item.GetType() == _allowedType) { list.Add(item); } else { throw new InvalidOperationException("集合只能存储同一类型的实例(B或C)"); } } }
使用时直接调用Start.Add方法,而非list.Add,就能保证集合内元素类型统一,后续转换时更安全。
方案3:利用多态特性(面向对象的优雅解决)
如果b和c的业务意义相似,可以在抽象基类Base中定义抽象方法,让子类各自实现:
public abstract class Base { public int a { get; set; } // 定义抽象方法,子类实现专属逻辑 public abstract void PrintSpecificField(); } class B : Base { public int b; public B(int a, int b) { this.a = a; this.b = b; } public override void PrintSpecificField() { Console.WriteLine(b); } } class C : Base { public int c; public C(int a, int c) { this.a = a; this.c = c; } public override void PrintSpecificField() { Console.WriteLine(c); } }
调用时无需转换类型,直接调用基类方法即可:
s.list[0].PrintSpecificField(); // 自动调用B类的实现,输出2
内容的提问来源于stack exchange,提问作者user2401856
相关产品推荐
相关产品推荐

