Home > Enterprise >  UNITY, How can I get all properties from another C# class and put them into an enum
UNITY, How can I get all properties from another C# class and put them into an enum

Time:02-02

I have two classes:

public class Stats : MonoBehaviour
{
    // Primary Stats
    public int strength;
    public int agility;
    public int intellect;
    public int stamina;
    public int spirit;
}

and

public class EquipmentProperties : ItemProperties
{
   public Stats stats;
}

public enum Stats
{//variables from "Stats" class to be in this enum
}

I am trying to get all the variables from the Stats class to be in the stats enum without having to manually enter them..

CodePudding user response:

"I am trying to get all the variables from the Stats class to be in the stats enum without having to manually enter them"

Enums must be specified at compile time, you can't dynamically add enums during run-time. If you would like to stablish the fields of your enum dynamically with your class variables, guess that because the Stats class might change along the app's development, you would need to store that enum somewhere, because if not you would need to access the fields of the dynamic enum according to that generic way of setting the enumeration, in a kind of meta-programming templated way that would not make much sense.

So along with your question comes the question of how to store that enum to be used afterwards I guess. For that you can check EnumBuilder class.

Extending that example, you can build the enum according to the specific Stats class like this:

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;

public class Stats
{
    // Primary Stats
    public int strength;
    public int agility;
    public int intellect;
    public int stamina;
    public int spirit;
}

class Example
{
    public static List<string> getFields(Type type) {
        var propertyValues = type.GetFields();
        var result = new Stats[propertyValues.Length];
        var retStr = new List<string>();
        for (int i = 0; i < propertyValues.Length; i  ) {
            retStr.Add(propertyValues[i].Name);
        }

        return retStr;
    }

    public static void Main() {
        // Get the current application domain for the current thread.
        AppDomain currentDomain = AppDomain.CurrentDomain;

        // Create a dynamic assembly in the current application domain,
        // and allow it to be executed and saved to disk.
        AssemblyName aName = new AssemblyName("TempAssembly");
        AssemblyBuilder ab = currentDomain.DefineDynamicAssembly(
            aName, AssemblyBuilderAccess.RunAndSave);

        // Define a dynamic module in "TempAssembly" assembly. For a single-
        // module assembly, the module has the same name as the assembly.
        ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name   ".dll");

        // Define a public enumeration with the name "Elevation" and an
        // underlying type of Integer.
        EnumBuilder eb = mb.DefineEnum("Stats", TypeAttributes.Public, typeof(int));

        int fieldCount = 0;
        getProperties(typeof(Stats)).ForEach(field => {
            eb.DefineLiteral(field, fieldCount);
            fieldCount  ;
        });

        // Define two members, "High" and "Low".
        //eb.DefineLiteral("Low", 0);
        //eb.DefineLiteral("High", 1);


        // Create the type and save the assembly.
        Type finished = eb.CreateType();
        ab.Save(aName.Name   ".dll");

        foreach (object o in Enum.GetValues(finished)) {
            Console.WriteLine("{0}.{1} = {2}", finished, o, ((int)o));
        }
        Console.ReadLine();
    }
}

Output:

Stats.strength = 0
Stats.agility = 1
Stats.intellect = 2
Stats.stamina = 3
Stats.spirit = 4

CodePudding user response:

This is of course not what you are asking directly since it is not automatic but I would suggest a Dictionary<Stats, int> and do e.g.

public class StatsComponent : MonoBehaviour
{
    // Make these only assignable via the Inspector
    [SerializeField] private int strength;
    [SerializeField] private int agility;
    [SerializeField] private int intellect;
    [SerializeField] private int stamina;
    [SerializeField] private int spirit;

    public readonly Dictionary<Stats, int> stats = new Dictionary<Stats, int>();

    private void Awake ()
    {
        // Initialize once with values from the Inspector
        stats.Add(Stats.Strength, strength);
        stats.Add(Stats.Agility, agility);
        stats.Add(Stats.Intellect, intellect);
        stats.Add(Stats.Stamina, stamina);
        stats.Add(Stats.Spirit, spirit);
    }
}

public enum Stats
{
    Strength,
    Agility,
    Intellect,
    Stamina,
    Spirit
}

Of course there are ways to automatize that via reflection but I'm sure it will bring you more headaches and issues then it is solving - that's only an opinion of course.


If you don't want to type things twice you could instead of an enum rather go by index or strings e.g. using SerializedDictionary you could simply have a

public SerializedDictionary<string, int> stats;

and fill it in the Inspector and not have your fields at all.

  •  Tags:  
  • Related