简体   繁体   中英

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...

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
    }

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

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
        }

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.]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM