[英]Accessing a property of derived class from the base class in C#
在 C# 中,当泛型列表仅包含基类时,访问派生类的属性的最佳方法是什么。
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<BaseClass> MyList = new List<BaseClass>();
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<T> OfType<T>(this IEnumerable list)
{
foreach (var obj in list)
{
if (obj is T)
yield return (T)obj;
}
}
或者,如果您有 Linq,则该函数位于命名空间 System.Linq 中。
BaseClass o = MyList[i];
if (o is ClassB)
{
object k = ((ClassB)o).PropertyB;
}
if (o is ClassA))
{
object j = ((ClassA)o).PropertyA;
}
如果您经常这样做,另一种选择是在列表上创建一个扩展方法,以返回正确键入的枚举。 IE
public static class MyBaseListExtensions
{
public static IEnumerable<ClassA> GetAllAs(this List<MyBaseClass> list)
{
foreach (var obj in list)
{
if (obj is ClassA)
{
yield return (ClassA)obj;
}
}
}
public static IEnumerable<ClassB> GetAllbs(this List<MyBaseClass> 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<MyBaseClass> list = new List<MyBaseClass>();
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 对于 a 实例来说是什么?
如果您执行手动运行时类型检查(inst 是 Foo),然后转换为具有所需属性的类型,则可以执行此操作。
您可能对泛型和子类有一些问题(在这种情况下,您应该返回 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<BaseClass> MyList = new List<BaseClass>();
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 并返回不同的值来返回不同的内容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.