Home > Enterprise >  Is there some way to improve my usage of C# generic so I don't need to duplicate some declarati
Is there some way to improve my usage of C# generic so I don't need to duplicate some declarati

Time:08-14

I'm designing a Stats system for a game (e.g. move speed, attack power, etc). I've landed on the following solution (stripped down for the purposes of the question)

Base class for all stats. A stat can be int, float, bool, etc.

public abstract class Stat<T> 
{
    public abstract T GetStat(int level) {}
}

Sample implementation of a stat for Attack Power, which is a float value:

public class AttackPower : Stat<float>
{
    float floatStat = 10f;

    public override float GetStat(int level)
    {
        return floatStat * level; //placeholder behaviour
    }
}

I want to be able to 'Level up' a stat while the game is running, so for example the player might want to increase their attack power. So I implemented this class to pair a Stat with a Level

public class RuntimeStat<T,Z> where T: Stat<Z>
{
    public int Level { get; private set; }
    T Stat { get; }

    Y Value => Stat.GetStat(Level);

    public RuntimeStat(T stat) 
    {
        Stat = stat;
    }

    public void LevelUp()
    {
        Level  ;
    }
}

And to actually use the stat, this is how it would work in the Character class:

public class SomeCharacterClass
{
    RuntimeStat<AttackPower, float> AttackPower;

    public SomeCharacterClass()
    {
        AttackPower = new RuntimeStat<AttackPower, float>();
    }

    public void Attack()
    {
        Debug.Log($"Attack for {AttackPower.Value} damage!");
    }
}

Notice that in my RuntimeStat I had to define 2 generic types, one for which stat class I want to use at runtime (AttackPower), and what kind of value I'm expecting (float).

What I want to know is, is there some way I can improve this so that I don't need to define float twice in my code for AttackPower? AttackPower itself already extends Stat as a Stat<float> so it seems less than ideal to also have to define it for RuntimeStat

CodePudding user response:

I'm not sure why "stat" would need to be generic, however, what you are looking for is generic constraints.

Since .NET 6 (or perhaps only from .NET 7 (which should be released in a few months), since documentation for this isn't available for .NET 6) this has finally been enabled: INumber interface

So you can add where T : INumber.

I recommend you name the generic type TStat and not T though for clarity.

Once you have declared that the generic type is a number, you'll be able to use the Increment method via (documentation).

If you must use generics (which I doubt for this specific case) and you must use an older .NET version, you can write this less efficiently by checking the type of the generic type and calling the correct method accordingly in a case statement.

  • Related