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

C# 从C中的基类访问派生类的属性#,c#,generics,collections,C#,Generics,Collections,在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<Ba

在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        
    }
}
公共类ClassA:基类
{
公共对象属性{get;set;}
}
公共类ClassB:基类
{
公共对象属性b{get;set;}
}
公共类基类
{
}
公共排水干管
{
List MyList=新列表();
ClassA=新ClassA();
ClassB=新的ClassB();
添加(a);
添加(b);
for(int i=0;i
整个前提都没有意义-a实例的属性B是什么


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

泛型和子类可能存在一些问题(在这种情况下,应返回System.Collections.ArrayList),但必须将基类强制转换为要使用的子类。如果您使用'as'目录,如果基类可以强制转换为子类,那么它将成功;如果不能强制转换,那么它将为null。它看起来像:

   BaseClass o = MyList[i];
   if (o is ClassB)
   {
      object k = ((ClassB)o).PropertyB;
   }
   if (o is ClassA))
   {
      object j = ((ClassA)o).PropertyA;
   }
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;
    }
}
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
    }
}
for(int i=0;i

还有,我应该提一下,这闻起来有点难闻。这类代码表示结构不良的对象继承权。一般来说,如果不能说a是基类,那么您的设计可能是错误的。但是,希望这有帮助

你当然可以沮丧,就像这样:

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
    }
}

如果您经常这样做,另一个选择是在列表上创建一个扩展方法,以返回正确类型的枚举。i、 e

  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;
        }
      }
    }
  }
公共静态类MyBaseListExtensions
{
公共静态IEnumerable GetAllAs(此列表)
{
foreach(列表中的var obj)
{
if(obj为A类)
{
收益率回报(A类)obj;
}
}
}
公共静态IEnumerable GetAllbs(此列表)
{
foreach(列表中的var obj)
{
if(obj为B类)
{
收益率回报率(B类)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);
  }
}
private void按钮1\u单击(对象发送者,事件参数e)
{
ClassA a1=新的ClassA(){PropertyA=“Tim”};
ClassA a2=新的ClassA(){PropertyA=“Pip”};
ClassB b1=新的ClassB(){PropertyB=“Alex”};
ClassB b2=新的ClassB(){PropertyB=“Rachel”};
列表=新列表();
增加(a1);
增加(a2);
列表。添加(b1);
列表。添加(b2);
foreach(list.GetAllAs()中的var a)
{
列表框1.Items.Add(a.PropertyA);
}
foreach(list.GetAllbs()中的变量b)
{
列表框2.Items.Add(b.PropertyB);
}
}

您需要在基类中将属性声明为virtual,然后在派生类中重写它们

例:

公共类ClassA:基类
{
公共重写对象属性{get;set;}
}
公共类ClassB:基类
{
公共重写对象属性b{get;set;}
}
公共类基类
{
公共虚拟对象属性{get;set;}
公共虚拟对象属性b{get;set;}
}
公共排水干管
{
List MyList=新列表();
ClassA=新ClassA();
ClassB=新的ClassB();
添加(a);
添加(b);
for(int i=0;i
您可能需要在基类中实现该属性以返回默认值(例如null),或者将其抽象并强制所有派生类实现这两个属性


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

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

public static IEnumerable<T> OfType<T>(this IEnumerable list)
{
    foreach (var obj in list)
    {
        if (obj is T)
            yield return (T)obj;
    }
}
类型的公共静态IEnumerable(此IEnumerable列表)
{
foreach(列表中的var obj)
{
if(obj是T)
收益率(T)obj;
}
}

或者,如果您有Linq,则该函数位于命名空间系统中。Linq。

我使用第二个代码示例访问派生类中的属性……感谢您的输入。这太棒了。我到处搜索,发现这么多线程都说这是不可能的,但这个解决方案非常有效。我肯定遗漏了一些东西,但是如果您只是想在派生类中编写,为什么需要
BaseClass
中的
DoStuff()
?您是否可以使用接口强制在派生类中包含
DoStuff()
?@SteveCinq,因为这样,您就可以在基类对象上调用该方法,而不必知道该类的确切派生类型。
public static IEnumerable<T> OfType<T>(this IEnumerable list)
{
    foreach (var obj in list)
    {
        if (obj is T)
            yield return (T)obj;
    }
}