Home > Back-end >  How to store subclass types and be able to instantiate a variable with the position of the list?
How to store subclass types and be able to instantiate a variable with the position of the list?

Time:12-29

I'm developing a game in C# on Unity that aims to learn basics in Python.

In my project I have created an abstract class Execution which defines the different types of executions in Python :

public abstract class Execution
{
    public enum ExecutionType
    {
        Affectation,
        Incrementation,
        Decrementation,
        Multiplier,
        Divisor,
        EntireDivisor,
        Modulo,
        IfStatement,
        ElseStatement,
        ForLoop,
        WhileLoop,
        Pass,  
    }
    
    public ExecutionType Type;

    public abstract string Representation();

    public Execution(ExecutionType type)
    {
        type = Type;
    }

    // Some others methods

}

And here is an example of a class that derives from Execution :

public class Pass : Execution
{
    public Pass() : base(ExecutionType.Pass) { }

    public override string Representation()
    {
        return IndentRepresentation($"<color=#eb8f34>pass</color>");
    }
}

All this allows me to create a random Python code generator in another script, so I started to think about an algorithm that allows to generate a Python code that works by instantiating for each line a class derived from the Execution class.

int randomIndex = 0; // Generated in the algorithm

List<Type> ExecutionsTypes = new List<Type>();
ExecutionsTypes.Add(typeof(Affectation)); // Error
ExecutionsTypes.Add(typeof(Pass));

Execution execution = (Execution)Activator.CreateInstance(ExecutionsTypes[randomIndex]); // Sometimes errors

My problem is that I want to store all the types of these classes in a list and be able to instantiate them by browsing the list but yet, some classes are generic classes (so I have an error in those places) but others have necessary arguments, and since the choice is random, I can't know how to put the necessary arguments.

CodePudding user response:

In order to use Activator.CreateInstance(someType) each type must have a parameterless constructor. You indicated that sometimes you get an error, so it's apparent that some of your classes don't. Even if they did that's a difficult design because later you might want to add a type without a default constructor and you won't be able to.

One approach is to create a list of instantiated classes instead of a list of types.

Instead of this:

List<Type> executionsTypes = new List<Type>();
executionsTypes.Add(typeof(Affectation));
executionsTypes.Add(typeof(Pass));

do this:

List<Execution> executions = new List<Execution>();
executions.Add(new Affectation()); 
executions.Add(new Pass());

Then instead of selecting a type from the list and having to instantiate it, you can select a class instance that's already been instantiated.

What if you don't want to re-use class instances and you need a new one each time? Then you could do this:

List<Func<Execution>> executions = new List<Func<Execution>>();
executions.Add(() => new Affectation()); 
executions.Add(() => new Pass());
executions.Add(() => new SomeTypeWithParameters("x", 1));

Then what you select from the list is a function that returns an Execution, and you call it to create a new instance.

Func<Execution> createExecutionFunction = // however you randomly select one
Execution execution = createExecutionFunction();
  • Related