-1

So i wanted to store categories of data within my "player" class with static classes so that they are named variables and are callable by name. I recently found a solution for calling variables within a class by their string name to get and set them here: C# setting/getting the class properties by string name and i tried to call the static class via string by using "Type.GetType(pattern)": Get class by string value

I attempted to modify the object to also call the static class by a string but I am missing something because get and set doesn't work at all:

public class Player
{

    //categories of variables within static classes
    public static class Status { public static int health = 10, stamina = 10, mana = 10; };
    public static class Immunity { public static bool fire = false, water = false, giantEnemyCrab = true; };
    //paralell arrays 
    public string[] namelistStatus = { "health", "stamina", "mana" };
    public string[] namelistImmunity = { "fire", "water", "giantEnemyCrab" };


    //get and set Variables from nested classes
    //('classname' is the name of the class,'propertyName' is the name of the variable)
    public object this[string className, string propertyName]
    {
        //indirectly calls variables within static classes entirely via string
        get
        {

            //i think the problem originates from "Type.GetType(className)" not being the correct way to call the static class by their string name
            Type myType = Type.GetType(className);
            PropertyInfo myPropInfo = myType.GetProperty(propertyName);
            return myPropInfo.GetValue(this, null);
        }
        set
        {

            Type myType = Type.GetType(className);
            PropertyInfo myPropInfo = myType.GetProperty(propertyName);
            myPropInfo.SetValue(this, value, null);
        }
    }
    //display variables
    public void DisplayPlayerStatus()
    {
        for (int i = 0; i < namelistStatus.Length; i++)
        {
            Console.WriteLine(namelistStatus[i]+":"+this["Status", namelistStatus[i]]);
        }
        for (int i = 0; i < namelistStatus.Length; i++)
        {
            if (Convert.ToBoolean(this["Immunity", namelistStatus[i]]))
            {
                Console.WriteLine(namelistStatus[i] + " Immunity");
            }
        }
    }

}

That was a simplification of the Player class I'm trying to organize with nested static classes, there are also some functions that are meant to set the variables in the status and immunity classes but here i only made an example function for 'getting' the nested static class variables via string but 'setting' doesn't work either. Any suggestions of how i would be able to do this properly would be much appreciated.

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
DED
  • 391
  • 2
  • 12
  • 1
    `IIrrrrksss.` static inner class? why? Why not simply give your class a dictionary and use the indexer on that? Inside your indexer you can even use a `TryGet()` approach on your dictionary to avoid keys if one player is a mage and another a warrior and your game tries to fish for a `"magical_damage"` value of your fighter – Patrick Artner Jun 16 '18 at 11:38
  • Why are you even attempting to do this? Do all players share the same Status? I wouldn't think so. Just take Status and Immunity out of the Player class and make them non-static. There's no reason for an entity class (as those are) for being static, specially with shared state. – Camilo Terevinto Jun 16 '18 at 11:41

1 Answers1

0

Problems:

  • Your static inner classes are just that - nested Types inside your Player class - not properties of your Player class.

  • Your properties inside your static class are actually Fields.

  • You used the wrong name list for Immunities inside Player.DisplayPlayerStatus()

You could ( but you really should NOT , reconsider your design ) fix it like this

public class Player
{
    public string[] namelistImmunity = { "fire", "water", "giantEnemyCrab" };
    public string[] namelistStatus = { "health", "stamina", "mana" };

    public object this[string className, string propertyName]
    {
        //indirectly calls variables within static classes entirely via string
        get
        {
            var innerClass = GetType().GetNestedType(className);
            var myFieldInfo = innerClass?.GetField(propertyName);
            return myFieldInfo.GetValue(null);
        }
        set
        {
            var innerClass = GetType().GetNestedType(className);
            var myFieldInfo = innerClass?.GetField(propertyName);
            myFieldInfo?.SetValue(null, value);
        }
    }

    public void DisplayPlayerStatus()
    {
        // why for and indexing - foreach is far easier
        foreach (var s in namelistStatus)
            Console.WriteLine(s + ":" + this["Status", s]);

        // you used the wrong list of names here 
        foreach (var n in namelistImmunity) 
            if (Convert.ToBoolean(this["Immunity", n]))
                Console.WriteLine(n + " Immunity");
    }

    public static class Immunity 
    {
        // these are fields 
        public static bool fire = false, 
                           water = false, 
                           giantEnemyCrab = true; 
    };

    public static class Status 
    {
        // fields as well 
        public static int health = 10, 
                      stamina = 10, 
                      mana = 10; 
    };
}

Tested with:

using System; 

internal class Program
{
    public static void Main(string[] args)
    {
        Player p = new Player();
        p.DisplayPlayerStatus();

        Console.WriteLine();

        p["Status", "health"] = 200;
        p.DisplayPlayerStatus();

        Console.ReadLine();
    }

    // the fixed stuff goes here
}

Output:

health:10
stamina:10
mana:10
giantEnemyCrab Immunity

health:200
stamina:10
mana:10
giantEnemyCrab Immunity

Your classes are currently very tighty coupled, if you add psyonicPower to your stats, you need to edit your Player, edit Player.Status, modify Player.namelistStatus.

You could autodiscover the static class fieldnames via reflection in a similar fashion like you access the field-values and get rid of both your namelistXXXX - but still, the design is bad.

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
  • Ok thanks! I should've been using dictionaries for this instead but I didn't know they were a thing. Still cool to know that doing this my way would still work but it would be less efficient. – DED Jun 17 '18 at 01:32