C# Access inherited class properties from list of base class

4.9k views Asked by At

First, I create base class and inherited class

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

And then I create list of base class to store all inherited class

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

Later, I try to access a member of inherited class in list

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

Yeah, I got an error : 'Entity' does not contain a definition for 'position'and no extension method 'position' accepting a first argument of type 'Entity' could be found (are you missing a using directive or an assembly reference?)

Is there a probably way to access inherited class properties from list of base class?

3

There are 3 answers

5
Clint On BEST ANSWER

You need to cast the Entity instance to an EntityObject instance, because the Position field is indeed not part of Entity

So:

var entityObjectInEntityList = (EntityObject)entityList[0]

Will give you the correct type, which you can then access the .Position field against.


As mentioned in the comments, you could also test the type / do the cast the following ways:

if(entityList[0] is EntityObject)

Just testing type - usually avoided as you still need to cast to get the correct type and that involves overhead

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

OR with C# 6

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

Using the as keyword to perform a cast, and return a null if it fails.


In the interests of mercy, as pointed out by Henk, you're clearly trying to include some type information in your class, in the form of the EntityType property.

You can determine the type of an object at runtime:

var type = instance.GetType();

Therefore:

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

will tell you the type of the instance, but using things like type checking of derived classes is often a smell.

Assuming you don't need any base functionality on Entity I would recommend going with an interface approach instead.

I'd recommend looking here: Interface vs Base class

0
T. Google On

I agree with Facundo La Rocca (below), you have to cast the object to the type you want to work with before you access its properties. However, if you are going to add multiple different EntityTypes (Object, Character, etc.) then you can still leave it as a base List of Entity. You just have to make sure that for each different type of Entity in your list, you check (and cast) to which one it is:

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;
    }
2
Facundo La Rocca On

This is because you've declared your list as List<Entity>, but you are trying to use it as List<EntityObject>.

I think in your case you should declare your list as List< EntityObject>.

The other way is to cast your element as EntityObject like this:

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

What way you take depends on your bussiness model, your preference, semantic and your propose. In this case the question would be:

  • Why did you define your list as List<Entity> and then you manage it as List<Entitybject>?