【问题标题】:C# Access inherited class properties from list of base classC#从基类列表访问继承的类属性
【发布时间】:2017-05-23 19:13:32
【问题描述】:

首先,我创建基类和继承类

public class Entity
{
   public int EntityID;
   public EntityType type = EntityType.NONE;
}

public class EntityObject : Entity
{
   public Vector2 position;
   public EntityObject()
   {
      position = Vector2.Zero;
      type = EntityType.OBJECT;
   }
}

然后我创建基类列表来存储所有继承的类

List<Entity> entityList = new List<Entity>();
entityList.Add(new EntityObject());

稍后,我尝试访问列表中继承类的成员

for(int i = 0; i < entityList.Count; i++)
    if(entityList[i].type == EntityType.OBJECT)
        entityList[i].position = Vector2.One;

是的,我收到一个错误:“实体”不包含“位置”的定义,并且找不到接受“实体”类型的第一个参数的扩展方法“位置”(您是否缺少 using 指令或汇编参考?)

有没有办法从基类列表中访问继承的类属性?

【问题讨论】:

  • 一个单独的考虑是当您只需要 IEnumerable 实现时,您使用相对重量级的 List 类。

标签: c# xna-4.0


【解决方案1】:

您需要将Entity 实例转换为EntityObject 实例,因为Position 字段确实不是Entity 的一部分

所以:

var entityObjectInEntityList = (EntityObject)entityList[0]

将为您提供正确的类型,然后您可以访问 .Position 字段。


如 cmets 中所述,您还可以通过以下方式测试类型/进行强制转换:

if(entityList[0] is EntityObject)

只是测试类型 - 通常避免,因为您仍然需要强制转换以获得正确的类型并且涉及开销

var item = entityList[0] as EntityObject;
if (item != null)
{
   var position = item.Position;
}

与 C# 6 或

var position = (entityList[0] as EntityObject)?.Position;

使用 as 关键字执行强制转换,如果失败则返回 null。


出于仁慈的考虑,正如 Henk 所指出的,您显然是在尝试以 EntityType 属性的形式在您的类中包含一些类型信息。

您可以在运行时确定对象的类型:

var type = instance.GetType();

因此:

if(itemInList.GetType() == typeof(EntityObject))

会告诉你实例的类型,但使用派生类的类型检查之类的东西通常是一种味道。

假设您不需要 Entity 上的任何基本功能,我建议您改用接口方法。

我建议看这里:Interface vs Base class

【讨论】:

  • 来吧,也更换DIY类型系统。
  • 比显式强制转换更好,将as 关键字与空检查结合使用。见stackoverflow.com/questions/496096/…
  • 是的,我也没有想到 GetType()。 isas 存在多种解决方案。
  • 我尽量避免 GetType 和 as / 作为一般规则不惜一切代价,更喜欢使用体面的接口结构,只是期待符合我所追求的功能的接口在呼叫现场。
  • 感谢您的所有解决方案和评论,现在我可以继续工作了。非常感谢。
【解决方案2】:

这是因为您已将列表声明为List&lt;Entity&gt;,但您正试图将其用作List&lt;EntityObject&gt;

我认为在你的情况下你应该将你的列表声明为 List

另一种方法是将元素转换为 EntityObject,如下所示:

((EntityObject )entityList[i]).position = Vector2.One;

你采取什么方式取决于你的商业模式、你的偏好、语义和你的提议。在这种情况下,问题是:

  • 为什么将列表定义为List&lt;Entity&gt;,然后将其管理为List&lt;Entitybject&gt;

【讨论】:

  • 因为有各种继承的类要存储在list中,所以我声明为List
  • 完美,在这种情况下你必须施放它们。但是您可能希望更清楚地拆分为方法。
【解决方案3】:

我同意 Facundo La Rocca(下)的观点,您必须先将对象转换为您想要使用的类型,然后才能访问其属性。但是,如果您要添加多个不同的实体类型(对象、字符等),那么您仍然可以将其保留为实体的基本列表。您只需确保对于列表中的每种不同类型的实体,您检查(并强制转换)它是哪一个:

public static void Main(string[] args){
    var entityList = new List<Entity>();
    entityList.Add(new EntityObject()); 

    for(int i = 0; i < entityList.Count; i++) {
        if(entityList[i] is EntityObject)
            ((EntityObject)entityList[i]).position = Vector2.One;
        else if (entityList[i] is EntityCharacter)
            ((EntityCharacter)entityList[i].characterProperty = someValueToSet;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-01
    • 2013-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多