简体   繁体   中英

Instantiating an Inherited class from a string

I'm wondering if there is an easy way to instantiate an inherited object (knowing the class name).

Assuming I have

public abstract Monster{
    public string name;
    public string specie;
    public Stats baseStats;
    public string imgDir;
}

and

public Specie1 : Monster{
    public new string specie = "Specie1";
    public new Stats baseStats = {1,2,3,4,5};
    public new imgDir = "dir/specie1.png";
    public Specie1(string n){
        name = n;
    }
}

My objective is to load from saved file the monsters, testing it with only one specie, I do the following:

Monster[0] = new Specie1("foo");

But in the event that I have many species, is there a way to instantiate generically?

For example:

string specie = loadSpecie();
Monster[] = new specie("foo");

I am hoping there is a way to do this without creating a lot of switches and ifs everywhere.

I was thinking of creating a constructor

Monster(string species,string name){
    if(species == "Specie1"){
        return new Specie1(name);
    }
}

But I think that would be horrible programming, and not scalable at all.

You can use a factory method to instance the monster sub-classes.

public abstract Monster
{
    public string name;
    public string specie;
    public Stats baseStats;
    public string imgDir;

    public static Monster CreateMonster(string monster)
    {
        Type[] types = GetTypeInfo().Assembly.GetTypes();
        Type monsterType = types.FirstOrDefault(t => t.Name.ToLower().Equals(monster.ToLower()));

        if (monsterType == null)
            throw new InvalidOperationException("The given monster does not have a Type associated with it.");

        return Activator.CreateInstance(monsterType) as Monster;
    }
}

public class Cat : Monster
{
}

The CreateMonster method looks up all of the types in the current assembly and creates an instance of the first Type it finds that has a name that matches the monster name provided. You would probably want to include some logic so that it doesn't try to instance an abstract class, and ensure the type is actually a child class of Monster.

Personally I would probably decorate the monster sub-classes with an attribute that gives a friendly name to each class. I would save the attribute value to the file, and to the first Type that has an attribute matching the monster name. I would also only do the GetTypes() call once. You should cache the result in a private static field in the Monster class. This way, you only use reflection once. In any event, the above code works and can be used like this:

Monster cat = Monster.CreateMonster("Cat");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM