Jacob Proffitt
Jacob Proffitt

Reputation: 12768

How to create a simplified assignment or default property for a class in C#

This is minor, I know, but let's say that I have a class Character and a class Ability (mostly because that's what I'm working on). Class Character has six abilities (so typical D&D...). basically:

public class Character
{
    public Character()
    {
        this.Str = new Ability("Strength", "Str");
        this.Dex = new Ability("Dexterity", "Dex");
        this.Con = new Ability("Constitution", "Con");
        this.Int = new Ability("Intelligence", "Int");
        this.Wis = new Ability("Wisdom", "Wis");
        this.Cha = new Ability("Charisma", "Cha");
    }

    #region Abilities
    public Ability Str { get; set; }
    public Ability Dex { get; set; }
    public Ability Con { get; set; }
    public Ability Int { get; set; }
    public Ability Wis { get; set; }
    public Ability Cha { get; set; }
    #endregion
}

and

public class Ability
{
    public Ability()
    {
        Score = 10;
    }
    public Ability(string Name, string Abbr)
        : this()
    {
        this.Name = Name;
        this.Abbr = Abbr;
    }

    public string Name { get; set; }
    public string Abbr { get; set; }
    public int Score { get; set; }
    public int Mod
    {
        get
        {
            return (Score - 10) / 2;
        }
    }
}

When actually using these ability properties in future code, I'd like to be able to default to just the score, like so:

//Conan hits someone
int damage = RollDice("2d6") + Conan.Str;

//evil sorcerer attack drains strength
Conan.Str = 0;

rather than:

//Conan hits someone
int damage = RollDie("2d6") + Conan.Str.Score;

//evil sorcerer attack drains strength
Conan.Str.Score = 0;

Now, the first case can be taken care of with an implicit conversion:

public static implicit operator int(Ability a)
{
    return a.Score;
}

Can anybody help me with the reverse? Implicit conversion like this:

public static implicit operator Ability(int a)
{
    return new Ability(){ Score = a };
}

will replace the entire attribute rather than just the score of the attribute—not the desired result...

Upvotes: 6

Views: 390

Answers (4)

GianT971
GianT971

Reputation: 4523

First, keep your implicit conversion:

public static implicit operator Ability(int a)
{
     return new Ability(){ Score = a };
}

Then in your character class: Add a private Ability attribute for str, and change the getter and the setter of the Str property as follows:

    private Ability str;
    public Ability Str 
    {
        get
        {
            return this.str;
        }
        set
        {
            if (value.Name == "")
            {
                this.str.Score = value.Score;
            }
            else
            {
                this.str = value;
            }
        }
    }

There you go :)

You could also use:

                if(string.IsNullOrWhiteSpace(value.Name))

instead of

                if (value.Name == "")

If you are compiling to .NET 4.0 version

EDIT: I gave you a solution that does exactly what you wanted to, but What ja72 wrote is also a good suggestion with operators + and -; you can add his solution to mine (or mine to him, whatever), it will work just fine. You will then be able to write:

        Character Jax = new Character(); // Str.Score = 10
        Character Conan = new Character(); // Str.Score = 10

        Jax.Str = 2000; // Str.Score = 2000;
        Conan.Str += 150; // Str.Score = 160

Upvotes: 3

Ian Mercer
Ian Mercer

Reputation: 39277

Perhaps you could make Ability abstract and then derive new classes from Ability for each of the sub-classes: Strength, ...

The constructor for the Strength class would look something like this:

public Strength () : base ("Strength", "Str") { ...}

Now the ability properties off a Character would be strongly typed and the implicit conversions could turn a value like 5 into a Strength object with a value of 5. This would also prevent you from accidentally storing a Dexterity in a Strength property, for example.

[Assuming the name and abbreviations are in fact fixed for all objects of that type.]

Upvotes: 0

John Alexiou
John Alexiou

Reputation: 29244

Another option is to replace the properties with delegates like this

public class Character
{
    public Character()
    {
        ...
    }

    #region Abilities
    ...
    #endregion

    public Func<int> Strength
    {
        get { return () => Str.Score; }
        set { Str.Score = value(); }
    }

}

and use it like this

        Character evil = new Character(); //Str.Sccore=10
        // fist spell hits
        evil.Strength = () => 5; //set Str.Score=5
        // second spell hits
        evil.Strength = () => 0; //set Str.Score=5

        if (evil.Strength() == 0)
        {
            // dead
        }

Upvotes: 1

John Alexiou
John Alexiou

Reputation: 29244

The best you can do is increment the score by adding these methods to Ability.

    public static Ability operator + (Ability lhs, int score)
    {
        lhs.Score += score;
        return lhs;
    }

    public static Ability operator - (Ability lhs, int score)
    {
        lhs.Score -= score;
        return lhs;
    }

    public static implicit operator int(Ability rhs)
    {
        return rhs.Score;
    }

and using them like:

    static void Main(string[] args)
    {
        Character evil = new Character(); //Str.Sccore=10

        evil.Str += 10; //cast spell for Str.Sccore=20

        evil.Str -= evil.Str; //death with Str.Sccore=0
    }

Upvotes: 4

Related Questions