我被分配了一个我正在努力完成的任务。我需要将一个随机的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
等),使问题复杂化,我需要随机器忽略Black
和White
。
枚举只是整数,因此整数可以被强制转换为枚举。我会这样做:
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
});
演示。