从C#中的基类访问派生类的属性

在C#中,当generics列表仅包含基类时,访问派生类的属性的最佳方法是什么。

public class ClassA : BaseClass { public object PropertyA { get; set; } } public class ClassB: BaseClass { public object PropertyB { get; set; } } public class BaseClass { } public void Main { List MyList = new List(); ClassA a = new ClassA(); ClassB b = new ClassB(); MyList.Add(a); MyList.Add(b); for(int i = 0; i < MyList.Count; i++) { //I would like to access PropertyA abd PropertyB from the derived classes } } 

当然你可以贬低,像这样:

 for (int i = 0; i < MyList.Count; i++) { if (MyList[i] is ClassA) { var a = ((ClassA)MyList[i]).PropertyA; // do stuff with a } if (MyList[i] is ClassB) { var b = ((ClassB)MyList[i]).PropertyB; // do stuff with b } } 

...但是,你应该再看一下你想要完成的事情。 如果您有需要获取ClassA和ClassB属性的公共代码,那么最好将对这些属性的访问包装到祖先类中的共享,虚拟属性或方法中。

就像是:

 public class BaseClass { public virtual void DoStuff() { } } public class ClassA : BaseClass { public object PropertyA { get; set; } public override void DoStuff() { // do stuff with PropertyA } } public class ClassB : BaseClass { public object PropertyB { get; set; } public override void DoStuff() { // do stuff with PropertyB } } 

继TimJ的答案之后,您可以编写一个适用于所有类型的扩展方法:

 public static IEnumerable OfType(this IEnumerable list) { foreach (var obj in list) { if (obj is T) yield return (T)obj; } } 

或者,如果您有Linq,该函数位于命名空间System.Linq中。

如果你这么做很多,另一种选择是在列表上创建一个扩展方法,以便返回正确类型的枚举。 即

  public static class MyBaseListExtensions { public static IEnumerable GetAllAs(this List list) { foreach (var obj in list) { if (obj is ClassA) { yield return (ClassA)obj; } } } public static IEnumerable GetAllbs(this List list) { foreach (var obj in list) { if (obj is ClassB) { yield return (ClassB)obj; } } } } 

然后你就可以像……那样使用它

 private void button1_Click(object sender, EventArgs e) { ClassA a1 = new ClassA() { PropertyA = "Tim" }; ClassA a2 = new ClassA() { PropertyA = "Pip" }; ClassB b1 = new ClassB() { PropertyB = "Alex" }; ClassB b2 = new ClassB() { PropertyB = "Rachel" }; List list = new List(); list.Add(a1); list.Add(a2); list.Add(b1); list.Add(b2); foreach (var a in list.GetAllAs()) { listBox1.Items.Add(a.PropertyA); } foreach (var b in list.GetAllbs()) { listBox2.Items.Add(b.PropertyB); } } 

整个前提没有意义 – PropertyB对于一个实例会是什么?

如果进行手动运行时类型检查(inst为Foo),然后转换为具有所需属性的类型,则可以执行此操作。

  BaseClass o = MyList[i]; if (o is ClassB) { object k = ((ClassB)o).PropertyB; } if (o is ClassA)) { object j = ((ClassA)o).PropertyA; } 

您可能在generics和子类中遇到一些问题(在这种情况下,您应该返回到System.Collections.ArrayList),但是您必须将BaseClass强制转换为您希望使用的子类。 如果使用’as’目录,如果BaseClass可以转换为子类,它将成功,如果无法转换它将为null。 它看起来像:

 for(int i = 0; i < MyList.Count; i++) { BaseClass bc = MyList[i]; ClassA a = bc as ClassA; ClassB b = bc as ClassB; bc.BaseClassMethod(); if (a != null) { a.PropertyA; } if (b != null) { b.PropertyB; } } 

另外,我应该提一下,这闻起来有点糟糕。 这是一种表示结构不良的对象层次结构的代码。 一般来说,如果你不能说IS A BaseClass,你的设计可能是错误的。 但是,希望有所帮助!

您需要在基类上将属性声明为虚拟,然后在派生类中覆盖它们。

例如:

 public class ClassA : BaseClass { public override object PropertyA { get; set; } } public class ClassB: BaseClass { public override object PropertyB { get; set; } } public class BaseClass { public virtual object PropertyA { get; set; } public virtual object PropertyB { get; set; } } public void Main { List MyList = new List(); ClassA a = new ClassA(); ClassB b = new ClassB(); MyList.Add(a); MyList.Add(b); for(int i = 0; i < MyList.Count; i++) { // Do something here with the Property MyList[i].PropertyA; MyList[i].PropertyB; } } 

您可能需要在基类中实现该属性以返回默认值(例如null)或使其成为抽象并强制所有派生类实现这两个属性。

您还应该注意,通过在两个派生类中重写它并返回不同的值,您可以为PropertyA返回不同的内容。