Convert Parent class to Child class from a method

I have a class named Skills

public class Skills : ScriptableObject
{
    public string type;
}

and it has a child AttackSkill with some new variables (like damage and etc.)

So i want to get to those variables in a script

public void SkillExec(Skills skill)
    {
        if (skill.type == "Attack")
        {
            //Error here!
            SkillAttack(skill);
        }
    }

    public void SkillAttack(AttackSkill skill)
    {
        //code here
    }

But it gives an error, because SkillExec() uses parent Skills class (this is so method can get different types of skills)

At first i also wanted to just use parent Skills type, but as i understood you can’t get children’s variables with a parent type

How can i make this code work? Am i thinking the wrong way?

I think all you need is a cast to the child type, which will fail if it isn’t that type.

The above is not a good way to do things however. For one, strings allow you to make typos. For two, you need custom code in SkillExec() to handle each different skill… that’s gonna get totally out of control.

Instead you may wish to consider interfaces.

Using Interfaces in Unity3D:

Check Youtube for other tutorials about interfaces and working in Unity3D. It’s a pretty powerful combination.

It would be a better idea to move SkillExec to the base class as an abstract method. This would force all derived classes to add their own implementation.

public abstract class Skill : ScriptableObject
{
    public abstract void Execute();
}

public sealed class AttackSkill : Skill
{
    public override void Exexcute()
    {
        // attack skill specific code here
    }
}
2 Likes

To answer your original question: you can usually use your IDE to fix errors like these automatically!

When you mouseover code in your IDE that has a red underline, you can see it say “Show potential fixes”.

If you press the keyboard shortcut or select Quick Actions from the context menu you will see some suggested fixes.

8464907--1124300--quick_actions.png

In this case the “Add explicit cast” suggestion will resolve the issue.

In addition to the explicit cast - which throws an error if the object can not be cast to AttackSkill - there are various other ways to perform casting:

As cast:

public void SkillExec(Skills skill)
{
    AttackSkill attackSkill = skill as AttackSkill; // if casting fails then null is assigned to attackSkill
    if(attackSkill != null)
    {
        SkillAttack(attackSkill);
    }

Is cast:

public void SkillExec(Skills skill)
{
    if(skill is AttackSkill attackSkill) // if casting fails then 'skill is AttackSkill' returns false and nothing is assigned to attackSkill
    {
        SkillAttack(attackSkill);
    }

1 Like

Thanks for the reply, are you suggesting to make an Interface instead of a parent Skill class and then modify SkillExec as needed?

Also, how can i replace the string variables to not make typos? Do i use enums?

This looks great for what i want, thanks.

By the way, why did you seal the AttackSkill class?

Sealing classes from which you don’t need to derive can improve performance for free, so I think it’s a good idea to seal everything by default in your own code.

You can always always just unseal them later if the need does arise to introduce additional derived classes.

1 Like

I’d just remove the skill string. If you want a method external to Skill that takes different skill types and does things with them, you could:

public void SkillExec(Skills skill)
    {
        if (skill is AttackSkill attackSkill)
        {
            SkillAttack(attackSkill);
        }
        // etc. for other types
    }

    public void SkillAttack(AttackSkill skill)
    {
        //code here
    }

But that’s probably not the best design, the inheritance things suggested above might be better. Or not, depends very much on what you’re doing.