C# noob question: Derived classes in method parameter

Hi all, I’m still pretty new to programming.
In the example below, I have a base class called Entity, which is then inherited by 3 other classes, Knight, Goblin and Rock.

Then in another script, I have a ReduceHealth() method that takes in Entity as parameter. Now the issue I’m having is I’ll have to recast each Entity that gets passed into the method in order to access their Health variable, which in turn creates a lot of duplicate codes.

Health wasn’t declared in the base class because the Rock doesn’t need one.

Is there a way to use a generic code that lets me handle this more efficiently? (see example near end of code)
Thanks!

example code

using UnityEngine;
using System.Collections;
using System.Collections.Generic;    // required for List

// Base class
public abstract class Entity
{
    protected string id = "None";

    // Accessor
    public string ID { get; set;}
}


// Derived classes
public class Knight : Entity
{
    protected int health;

    // Constructor
    public Knight()
    {
        this.ID = "Knight";
        Health = 3;
    }

    // Accessor
    public int Health { get; set; }
}

public class Goblin : Entity
{
    protected int health;

    // Constructor
    public Goblin()
    {
        this.ID = "Goblin";
        Health = 1;
    }

    // Accessor
    public int Health { get; set; }
}

public class Rock : Entity
{
    // I am a Rock. I can't die!

    // Constructor
    public Rock()
    {
        this.ID = "Rock";
    }
}


// Code testing class
public class ClassTest : MonoBehaviour
{
    public List<Entity> characterList = new List<Entity>();

    void Start()
    {
        Entity knight = new Knight();
        Entity goblin = new Goblin();
        characterList.Add(knight);
        characterList.Add(goblin);

        for (int i = 0; i < characterList.Count; i++)
        {
            ReduceHealth(characterList[i]);
        }
    }

    public void ReduceHealth(Entity who)
    {
        if (who is Knight)
        {
            // Recast it as Knight
            Knight k = who as Knight;
            k.Health--;
            Debug.Log(k.ID + "'s HP: " + k.Health);
        }
        else if (who is Goblin)
        {
            // Recast it as Goblin
            Goblin g = who as Goblin;
            g.Health--;
            Debug.Log(g.ID + "'s HP: " + g.Health);
        }

        // Generic code. How can I do this??
//       if (who is Rock)
//              return;
//
//        who.Health--;
//        Debug.Log(who.ID + "'s HP: " + who.Health);
    }
}

Multiple approaches.

  • Put the health on the base class. Ignore it on the rook. (Could be a bad idea)
  • Use reflection to access it. (Probably a bad idea)
  • Abandon inheritance and use component based design (Good idea).
2 Likes

Put your health variable in the entity class. Doesn’t matter that the rock doesn’t need it

1 Like

There are a couple of approaches to this. You can extend your inheritance chain to look like this:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;    // required for List
// Base class
public abstract class Entity
{
    protected string id = "None";
    // Accessor
    public string ID { get; set;}
}

public abstract class LivingEntity : Entity
{
protected int health;
public int Health {get; set;}
}

// Derived classes
public class Knight : LivingEntity
{
    protected int health;
    // Constructor
    public Knight()
    {
        this.ID = "Knight";
        Health = 3;
    }
    // Accessor
    public int Health { get; set; }
}
..

void DamageEntity(LivingEntity e, int damage)
{
e.Health -= damage;
}

Or use component based design. It can help avoid a huge inheritance chain that sometimes happens in situations like this. This is how unity works (you add components to a game object).

The best solution is often a mix between component based design and inheritance.

Remember inheritance means “is a” and component based design means “has a”

3 Likes

Thanks everyone! I can see how Inheritance can get messy down the line with all the chaining.

I’ve read up on Component based design and understood how it works generally, but the implementation is a bit over my head at the moment. I’ll look up a few more articles and see how it goes!

If that doesn’t pan out, I’ll just put the variables in Base class.

Edit:
I think I get it now! The Composition samples over here helped: language agnostic - Prefer composition over inheritance? - Stack Overflow