假设我有一个接受使用Flags属性修饰的枚举的函数。如果枚举的值是多个枚举元素的组合,我如何随机提取其中一个元素?我有以下但似乎必须有更好的方法。
[Flags]
enum Colours
{
Blue = 1,
Red = 2,
Green = 4
}
public static void Main()
{
var options = Colours.Blue | Colours.Red | Colours.Green;
var opts = options.ToString().Split(',');
var rand = new Random();
var selected = opts[rand.Next(opts.Length)].Trim();
var myEnum = Enum.Parse(typeof(Colours), selected);
Console.WriteLine(myEnum);
Console.ReadLine();
}
答案 0 :(得分:9)
您可以调用Enum.GetValues
来获取枚举定义值的数组,如下所示:
var rand = new Random();
Colors[] allValues = (Colors[])Enum.GetValues(typeof(Colors));
Colors value = allValues[rand.Next(allValues.Length)];
答案 1 :(得分:9)
var options = Colours.Blue | Colours.Green;
var matching = Enum.GetValues(typeof(Colours))
.Cast<Colours>()
.Where(c => (options & c) == c) // or use HasFlag in .NET4
.ToArray();
var myEnum = matching[new Random().Next(matching.Length)];
答案 2 :(得分:2)
如果你不介意一点点强制转换,并且你的枚举是基础int类型,那么以下内容将起作用并且速度很快。
var rand = new Random();
const int mask = (int)(Colours.Blue | Colours.Red | Colours.Green);
return (Colours)(mask & (rand.Next(mask) + 1));
如果您只想设置一个标志,则可以执行以下操作:
var rand = new Random();
return (Colours)(0x1 << (rand.Next(3)));
答案 3 :(得分:1)
如果我理解正确,问题是关于从标志枚举值返回一个随机枚举值,而不是从标志枚举中返回一个随机成员。
[Flags]
private enum Shot
{
Whisky = 1,
Absynthe = 2,
Pochin = 4,
BrainEraser = Whisky | Absynthe | Pochin
}
[Test]
public void Test()
{
Shot myCocktail = Shot.Absynthe | Shot.Whisky;
Shot randomShotInCocktail = GetRandomShotFromCocktail(myCocktail);
}
private static Shot GetRandomShotFromCocktail(Shot cocktail)
{
Random random = new Random();
Shot[] cocktailShots = Enum.GetValues(typeof(Shot)).
Cast<Shot>().
Where(x => cocktail.HasFlag(x)).ToArray();
Shot randomShot = cocktailShots[random.Next(0, cocktailShots.Length)];
return randomShot;
}
修改强>
显然你应该检查枚举是否是有效值,例如:
Shot myCocktail = (Shot)666;
修改强>
简化
答案 4 :(得分:0)
在我的情况下-我的枚举缺少成员,例如0x01, 0x02, 0x08
,而大型ulong
枚举的最大值为0x200000000
。
此代码适用于我所有的情况:
/// <summary>
/// Gets <see cref="System.Random"/> instance.
/// </summary>
public static Random Random { get; } = new Random(Guid.NewGuid().GetHashCode());
/// <summary>
/// Gets random combination of Flags Enum.
/// </summary>
/// <typeparam name="T">Enum type.</typeparam>
/// <returns>Random Flags Enum combination.</returns>
public static T GetRandomFlagsEnumValue<T>()
where T : Enum
{
var allValues = (T[])Enum.GetValues(typeof(T));
ulong numberValue = allValues.OrderBy(x => Random.Next())
.Take(GetRandomInteger(1, allValues.Length - 1))
.Select(e => Convert.ToUInt64(e, CultureInfo.InvariantCulture))
.Aggregate((a, c) => a + c);
return (T)Enum.ToObject(typeof(T), numberValue);
}