-1

I'm trying to create a function that takes two player classes, compares which AttackElement they used, and is able to alter each class' variables based on which AttackElement has a better advantage.

I'm sure there's a much more logical way of doing this, but at the moment I'm stuck wondering if I could concatenate a string to call the correct variable. For example, if I am trying to access a variable in a player class called WaterStrength can I simply have a string that combines the word "Water" with "Strength" in order to call the variable? I know calling functions/variables doesn't normally work that way, but in this example I'm calling this iWantToCombineThis.

int baseDamage = 2;

class PlayerClass(){
      int Health = 10;
      int WaterStrength = 1;
      int FireStrength = 1;
}

void AnalyzeRound(PlayerClass won, PlayerClass lost, string winningElement)
        {
            string iWantToCombineThis = winningElement + "Strength";
            lost.Health -= baseDamage * won.iWantToCombineThis;
        }

AnalyzeRound(Player1,Player2,"Water");
AnalyzeRound(Player2,Player1,"Fire");

3 Answers3

3

You could use a Dictionary<string, Func<PlayerClass, int>> to get the value without resorting to reflection. Try this:

int baseDamage = 2;

class PlayerClass
{
    public int Health = 10;
    public int WaterStrength = 1;
    public int FireStrength = 1;
}

private Dictionary<string, Func<PlayerClass, int>> indirect = new Dictionary<string, Func<PlayerClass, int>>()
{
    { "WaterStrength", pc => pc.WaterStrength },
    { "FireStrength", pc => pc.FireStrength },
};

void AnalyzeRound(PlayerClass won, PlayerClass lost, string winningElement)
{
    int strength = indirect[winningElement + "Strength"](won);
    lost.Health -= baseDamage * strength;
}
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
3

A better approach would be to make the strength type an enum:

public enum StrengthType
{
    Water=1,
    Fire=2
}

And then have a method on the player class to get the Strength value for a given type from a dictionary mapping strength types to int values:

private Dictionary<StrengthType, int> strengthTypes = new Dictionary<StrengthType, int> 
{
   [StrengthType.Water] = 12,
   [StrengthType.Fire] = 15
};

public int GetStrength(StrengthType strengthType)
{
   return strengthTypes[strengthType];
} 
ProgrammingLlama
  • 36,677
  • 7
  • 67
  • 86
Ian Mercer
  • 38,490
  • 8
  • 97
  • 133
  • +1 to using enums and a dictionary lookup. You could also use a switch/if statement on enums to select different functions or box/unbox objects. – Slipoch Jul 08 '19 at 03:12
  • Thank you all, I was actually using enums before but decided to simplify it for the purpose of this question. I hadn't considered using a Dictionary and that really seems like the best approach. I'm learning on my own and still so new to it all that I don't know what all is possible or best practices. – TheFlyingElbow Jul 08 '19 at 05:09
1

Disclaimer: As the comments have noted, this is kind of an anti pattern and consider doing it statically.

But to answer your question, you could use reflection to do this:

public static class Utility
{
    static T GetDynamicValue<T>(this Object obj, string propertyName)
    {
        var flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
        var prop = obj.GetType().GetProperty(propertyName, flags);
        var val =prop.GetValue(obj);
        return (T)val;
    }
}

And then you can say:

var x = won.GetDynamicValue<int>("iWantToCombineThis");
lost.Health -= baseDamage * x;
Mike S
  • 3,058
  • 1
  • 22
  • 12