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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/210601/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 18:14:54  来源:igfitidea点击:

Accessing a property of derived class from the base class in C#

c#genericscollections

提问by Michael Kniskern

In C#, what is the best way to access a property of the derived class when the generic list contains just the base class.

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

采纳答案by Matt Hamilton

Certainly you can downcast, like so:

当然你可以垂头丧气,像这样:

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

... However, you should take another look at what you're trying to accomplish. If you have common code that needs to get to properties of ClassA and ClassB, then you may be better off wrapping access to those properties up into a shared, virtual property or method in the ancestor class.

... 但是,您应该再看看您要完成的工作。如果您有需要访问 ClassA 和 ClassB 属性的公共代码,那么最好将这些属性的访问权限封装到祖先类中的共享、虚拟属性或方法中。

Something like:

就像是:

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

回答by Adam Wright

The whole premise doesn't make sense - what would PropertyB be for the a instance?

整个前提没有意义 - PropertyB 对于 a 实例来说是什么?

You can do this if you do manual runtime type checking (inst is Foo), and then cast to the type with the property you want.

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

回答by tvanfosson

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

回答by tsimon

You might have some issues with Generics and subclasses (in which case you should go back to System.Collections.ArrayList), but you have to cast the BaseClass to the subclass you wish to use. If you use the 'as' directory, it will succeed if the BaseClass can be casted to the subclass, or it will be null if it cannot be cast. It would look something like:

您可能对泛型和子类有一些问题(在这种情况下,您应该返回 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;
    }
}

Also, I should mention that this smells a bit bad. This is the kind of code that indicates a poorly structured object heirarchy. In general, if you can't say a IS A BaseClass, your design is probably wrong. But, hope that helps!

另外,我应该提到这闻起来有点难闻。这种代码表明结构不良的对象层次结构。一般而言,如果您不能说 IS A BaseClass,则您的设计可能是错误的。但是,希望有帮助!

回答by Tim Jarvis

If you are doing this a lot, another option would be to create an extension method on the list to give you back the correctly typed enumeration. i.e.

如果您经常这样做,另一种选择是在列表上创建一个扩展方法,以返回正确键入的枚举。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;
        }
      }
    }
  }

Then you could use it like....

然后你可以像......一样使用它。

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

回答by Tim Jarvis

You would need to have the properties be declared as virtual on the base class and then override them in the derived class.

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

Ex:

前任:

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

You would either need to implement the property in the base class to return a default value (such as null) or to make it abstract and force all the derived classes to implement both properties.

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

You should also note that you could return different things for say PropertyA by overrideing it in both derived classes and returning different values.

您还应该注意,您可以通过在派生类中覆盖 PropertyA 并返回不同的值来返回不同的内容。

回答by Daniel Earwicker

Further to TimJ's answer, you can write one extension method that will work for all types:

除了 TimJ 的回答之外,您还可以编写一种适用于所有类型的扩展方法:

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

Or if you have Linq, that function is in the namespace System.Linq.

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