'C# How to access a class reference using a string

So, I have spent about 3 hours so far trying to find a solution
But, it is hard to understand the topics so high above my current knowledge.


QUESTION
If I have a base-class called Spell , and Sub-Classes such as HolySmite or DivineBuff , is there any possible way to access those classes by using a string?

MORE INFORMATION
I have a bunch of spells, ALL of them have simple variables such as refreshTimer or manaCost

I am trying to use one simple method called CastSpell()
This Method has about 30 lines of code such as:

  • is it time yet to cast spell?
  • do we have enugh mana to cast the spell?
  • did we complete casting the spell (because it took 10 seconds to cast it)?
    *

Currently, I am having to manually do all 30 lines of code multiplied by all the spells that I have, so far 30. It is very repetitive and makes it difficult read.

EXAMPLE Right now VERSUS what I want to do:

// this string can be any spell, I have 30 spells so far but will be adding more
    string spellName = "HolySmite";

    // Currently, I am having to write 30 lines of code attached below, and then I have to repeat the same damn thing for 30 spells
    // Lets just use only 1 line of code as an example...
    if (spellName == "HolySmite")
    {
        Spell.holySmite.castingNow = true;
    }

    // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< INSTEAD HOW CAN I GENERICALLY ACCESS THE CLASS FROM A STRING >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    Spell.spellName.castingNow = true;
    // Obviously, spellName does not exist inside the class. I just want to access the class called "HolySmite"
    // -- which is the variable stored in string spellName;
    //
    // Someone suggested using a Dictionary GET/SET inside the class:
    //
    //public class Spell
    //    {
    //        public Dictionary<string, SpellInfo> Spells = new Dictionary<string, SpellInfo>()
    //        {
    //             { nameof(HolySmite), new HolySmite() },
    //             { nameof(DivineBuff), new DivineBuff() }
    //         }
    //    }
    //    
    // However, using Dictionary prevents me access the subClass properties such as: refreshTimer, radius, damage, etc, etc, etc, etc
    //
    // THERE MUST BE SOME OTHER WAY!




HERE IS THE CLASS DEFINITIONS

public string spellName;

// My nested/inherted class
public abstract class SpellInfo
{
    public float timeToCastSpell;
    public float refreshTimer;
    public int manaCost;

    public float lastTimeCompleted;
    public float lastTimeAttempted;
    public bool castingNow;
    public abstract void Action();
}
// DERIVES from SpellInfo
public class HolySmite : SpellInfo
{
    public float radius;
    public int damage;

    public override void Action()
    {
        Debug.Log("Casting HolySmite");
    }
}
public class DivineBuff : SpellInfo
{
    public override void Action()
    {
        Debug.Log("Casting DivineBuff");
    }
}

public class Spell 
{
    public static HolySmite holySmite = new HolySmite();
    public static DivineBuff divineBuff = new DivineBuff();
}


Solution 1:[1]

Consider re-writing your spell class so that instead of having everything in a big long list of if statements, you use an interface to say a spell can act upon a target:

interface ISpell
{
    void CastOn(Player target);
}

Then your actual concrete spell class would look like:

class HolySmite : ISpell
{
    //other properties
    private int Damage = 15;

    public CastOn(Player target)
    {
        target.Health -= Damage;
    }
}

class DivineBuff : ISpell
{
    //other properties
    private int Resistance = 0.1;

    public CastOn(Player target)
    {
        target.Resistance += Resistance;
    }
}

Then, only the CastOn method needs to know about all the properties of the spell, and you can use a dictionary like you were recommended:

Dictionary<string, ISpell> Spells = new Dictionary<string, ISpell> 
{
    {nameof(HolySmite), new HolySmite()},
    {nameof(DivineBuff), new DivineBuff()}
};

Then, when you cast a spell, you simply say

var spellName = "HolySmite";
Spells[spellName].CastOn(myTarget);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 RoadieRich