在Collection中存储对公共字段的引用

时间:2016-12-12 10:25:48

标签: c#

我有一个名为武器的课程,它存储名为力量,敏捷,活力,智力的公共领域。 (输入Int32)

在武器对象的构造函数中,我有一个方法可以随机选择其中一个属性'并为其赋值。

Random random = new Random();
int primary = random.Next(0, 4);
if (//Condition met)
{
    switch (primary)
    {
        case 0:
            Strength = ...
            break;
        case 1:
            Dexterity = ...
            break;
        case 2:
            Vitality = ...
            break;
        case 3:
            Intelligence = ...
            break;
    }
}

我觉得这段代码难看并难以维护。

有没有办法存储这些'属性'在数组或列表中?然后,Random将在0和Attributes.Length之间进行选择,并相应地分配一个值。

有点像这样(这不会让你理解)

Random random = new Random();
int[] attributes = {this.Strength, this.Dexterity, this.Vitality, this.Intelligence};
int index = random.Next(0, attributes.Length);
//lets say 0, so index = Strength
if (//Condition met)
{
   //This is the part where index would be 0 so the program would assign 'Strength' a value
}

该值应分配给Array中选择的字段。不是数组中的元素。

这在以后开发继承类

时会有很大帮助

5 个答案:

答案 0 :(得分:2)

可以使用unsafe代码和指针完成,但更安全的方法可以使用多种方法:

Action<int>[] stats = { i => Strength = i, i => Dexterity = i, i => Vitality = i, i => Intelligence = i };

stats[new Random().Next(stats.Length)](123); // set random stat to 123

答案 1 :(得分:1)

我建议你使用Hashmap。你可以通过put和get方法避免多个switch和case语句。

答案 2 :(得分:1)

您可以使用enum

enum Attributes {Strength, Dexterity, Vitality, Intelligence};

然后你可以switch

switch (chosenAttribute)
    {
        case Attributes.Strength:
            ...
            break;
        case Attributes.Dexterity:
            ...
            break;
        case Attributes.Vitality:
            ...
            break;
        case Attributes.Intelligence:
            ...
            break;
    }

答案 3 :(得分:1)

有不同的解决方法。 例如,您可以将所有属性包装到某个类中,如下所示,并使您的属性包围它:

public class ItemAttribute
{
    public int Value { get; set; }
}

public class Weapon
{
     private readonly ItemAttribute _strengthAttribute = new ItemAttribute();
     // ....

     private readonly ItemAttribute[] _attributes = new[] {_strengthAtribute};

     public int Strength
     {
         get { return _strengthAttribute.Value; }
         set { _strengthAttribute.Value = value; }
     }
}

在这种情况下,您可以使用一些额外的逻辑(例如处理最小/最大值)扩展您的属性。它被称为&#34;价值对象&#34;图案。

直接存储int值的集合(数组或字典 - 它并不重要)的另一种方法。并且还创建包装器属性。

答案 4 :(得分:1)

你有很多可能性,但你应该考虑哪一种最适合你的问题。假设您有一个基类用于所有项目:

public abstract class BaseItem { 
    // from this class other items derive
}

如果是这种情况,那么您可以创建简单的“地图”,将属性与某种“名称”连接起来。你可以在启动时做一次:

public abstract class BaseItem {
    static Dictionary<string, PropertyInfo> _attributes = null;

    public BaseItem() {
        if ( _attributes == null ) { 
            InitializeProperties(); 
        }
    }

    void InitializeProperties() {
        _attributes = new Dictionary<string, PropertyInfo>()

        var properties = typeof(BaseItem).GetProperties().Where( property => Attribute.IsDefined(property, typeof(ItemAttributeAttribute)));
        foreach(var property in properties) {
            string name = ((ItemAttributeAttribute)property.GetCustomAttribute(property, typeof(ItemAttributeAttribute))).AttributeName;
            _attributes.Add(name, property);
        }
    }
}

现在您可以添加此自定义属性ItemAttributeAttribute

public ItemAttributeAttribute : Attribute { string _Name; public string AttributeName { get { return _Name; } set { _Name = value; } } public ItemAttributeAttribute(string name) { _Name = name; } }

最后要做的是用名称绑定属性:

public abstract class BaseItem {

    // rest of code here ...

    [ItemAttribute("Agility")]
    int Agility;

    // rest of code here ...
}

这样,您可以轻松地将属性“绑定”到名称。现在您可以使用一些方法来分配值:

void SetValue(string name, object value) {
    if(_attributes.ContainsKey(name)) {
        _attributes[name].SetValue(this, value); // you can put this into BaseItem though
    }
}

使用您展示的示例,我将制作2个课程SwordShield,我会用随机值填充它们:

public class Sword : BaseItem {
    public Sword() : base() {
        string[] names = new string[] { "atk", "def", "weight", "something" };
        string choosen = names[new Random().Next() % names.Length];
        SetValue(choosen, new Random().Next() % 1337);
    }
}

public class Shield : BaseItem {
    public Shield() : base() {
        int rand = new Random().Next() % _attributes.Count();
        SetValue(_attributes.Keys[rand], new Random().Next() % 1337);
    }
}

当然,您必须记住在基类中设置所有属性,这可能是困难的,但您也可以对此方法进行一些改进。

对于所有Reflection仇恨者(我知道大多数SO用户都是这样):有时候最好使用这种方法,而不是制作无用的变量,方法和代码行的负载。