为属性分配随机枚举值



我被分配了一个我正在努力完成的任务。我需要将一个随机的enum分配给一个属性。我的代码是这样的。

public enum PegColour
{
    Red, Green, Blue, Yellow, Black, White
}

和其他类似于

的类
public class PegContainer
{
   /// <summary>
   /// Dfines the colour of the first peg
   /// </summary>
    public Peg Colour1 { get; set; }
    /// <summary>
    /// Dfines the colour of the secod peg
    /// </summary>
    public Peg Colour2 { get; set; }
    /// <summary>
    /// Dfines the colour of the third peg
    /// </summary>
    public Peg Colour3 { get; set; }
    /// <summary>
    /// Dfines the colour of the forth peg
    /// </summary>
    public Peg Colour4 { get; set; }
    public void GeneratePegs()
    {
    }
}

我的GeneratePegs()方法应该,每次它被称为随机分配一个enum颜色到一个属性(Colour1, Colour2等),使问题复杂化,我需要随机器忽略BlackWhite

枚举只是整数,因此整数可以被强制转换为枚举。我会这样做:

Random rnd = new Random();
public enum PegColour
{
    Red, Green, Blue, Yellow, Black, White
}
private PegColour GetRandomColoredPeg()
{
    PegColour color = (PegColour)rnd.Next(0, Enum.GetNames(typeof(PegColour)).Length - 2);
    return color;
}

黑色和白色将永远不会被选中,因为它只从前4种颜色中随机选择。只要在黑色和白色挂钩之前添加挂钩,即使从枚举中添加或删除挂钩,这段代码应该每次都能正常工作。所以如果你想添加新的颜色,你只需要把PegColour改成这样:

public enum PegColour
{
    Red, Green, Blue, Yellow, Purple, Orange, Pink, Black, White
}

您不需要更改任何其他内容!

所以你的GeneratePegs()方法应该是这样的:
public void GeneratePegs()
{
    Colour1 = GetRandomColoredPeg();
    Colour2 = GetRandomColoredPeg();
    Colour3 = GetRandomColoredPeg();
    Colour4 = GetRandomColoredPeg();
}

一个简单的解决方案是创建一个包含所有符合条件的值的数组:

PegColour[] eligibleValues = new[] { PegColour.Red, PegColour.Blue, PegColour.Green, PegColour.Yellow };

您可以使用Random的实例来随机选择该数组中的索引:

var myRandomColour = eligibleValues[myRandom.Next(eligibleValues.Length)];

这样做的一个优点是,您不必为enum常量分配任何特定的数值来进行随机选择。这样,如果需要,您仍然可以自由地为其他目的定义和使用数值。


现在,这个可能在PegColour频繁使用新元素扩展的情况下仍然有点不方便。在这种情况下,您可以在Enum.GetValues方法初始化后检索当前定义的常量的完整列表(注意,此代码片段假设已导入System.Linq名称空间,以允许从System.Linq.Enumerable访问扩展方法):
PegColour[] eligibleValues = Enum.GetValues(typeof(PegColour)).Cast<PegColour>().ToArray();

显然,这还没有满足排除某些颜色的要求。因此,您可以直接在数组创建表达式中硬编码此限制:

PegColour[] eligibleValues = Enum.GetValues(typeof(PegColour)).Cast<PegColour>().Where(pc => (pc != PegColour.Black) && (pc != PegColour.White)).ToArray();

…或者将要排除的颜色存储在某个集合中,使其更具可扩展性:

PegColour[] eligibleValues = Enum.GetValues(typeof(PegColour)).Cast<PegColour>().Where(pc => !myExcludedColours.Contains(pc)).ToArray();

注意,您总是可以放置这段代码,以便只初始化一次eligibleValues,而不是每次随机检索一个值。这避免了不必要的可能昂贵的GetValues调用,以及不必要地总是重新生成数组。

我建议你创建一个列表:

var pegs = new List<Peg> { Peg.Red, Peg.Green, Peg.Blue, Peg.Yellow };

然后使用这个问题的公认答案,随机排序。最后,将值赋给挂钩:

Colour1 = pages[0];
Colour2 = pages[1];
Colour3 = pages[2];
Colour4 = pages[3];

我为Random对象做了一个非常通用的扩展方法,该方法生成Enum类型的随机值。这适用于各种混乱的枚举,包括具有糟糕编号方案的枚举。这是通过使用Enum.GetValues来获取Enum的所有可能值来实现的。然后随机选取一个随机的可能值

public static TEnum GetRandomEnum<TEnum>(this Random rand, IEnumerable<TEnum> excludedValues)
{
    var type = typeof(TEnum);
    if (!type.IsEnum)
        throw new ArgumentException("Not an enum type");

    var values = Enum.GetValues(type).Cast<TEnum>();
    if (excludedValues != null && excludedValues.Any())
        values = values.Except(excludedValues); 
    //if you call this a lot, you could consider saving this collection in memory
    //   and separate the logic to avoid having to re-generate the collection

    //create a random index for each possible Enum value 
    //will never be out of bounds because it NextDouble returns a value
    //between 0 (inclusive) and 1 (exclusive)  or [0, 1)
    int randomIndex = (int) (rand.NextDouble() * values.Count());
    return values.ElementAt(randomIndex);
}   

这个扩展方法是这样调用的:

var randomColor = rand.GetRandomEnum<ColorType>(new List<Colors> 
{ 
    Colors.White, 
    Colors.Black
});

演示。

相关内容

  • 没有找到相关文章

最新更新