如何从枚举中选择一个随机值?

给定c#中的任意枚举,我如何选择一个随机值?

(我没有在SO上找到这个非常基本的问题。我将在一分钟内发布我的答案作为任何人的参考,但请随时发布你自己的答案。)

145397 次浏览

使用枚举。GetValues检索所有值的数组。然后选择一个随机的数组项。

static Random _R = new Random ();
static T RandomEnumValue<T> ()
{
var v = Enum.GetValues (typeof (T));
return (T) v.GetValue (_R.Next(v.Length));
}

测试:

for (int i = 0; i < 10; i++) {
var value = RandomEnumValue<System.DayOfWeek> ();
Console.WriteLine (value.ToString ());
}

->

Tuesday
Saturday
Wednesday
Monday
Friday
Saturday
Saturday
Saturday
Friday
Wednesday

Enum.GetValues;这将返回一个数组,表示枚举的所有可能值。从这个数组中随机选择一个项目。将该项强制转换回原始enum类型。

Array values = Enum.GetValues(typeof(Bar));
Random random = new Random();
Bar randomBar = (Bar)values.GetValue(random.Next(values.Length));
这是它的一个泛型函数。 保持RNG的创建在高频代码之外
public static Random RNG = new Random();


public static T RandomEnum<T>()
{
Type type = typeof(T);
Array values = Enum.GetValues(type);
lock(RNG)
{
object value= values.GetValue(RNG.Next(values.Length));
return (T)Convert.ChangeType(value, type);
}
}

使用的例子:

System.Windows.Forms.Keys randomKey = RandomEnum<System.Windows.Forms.Keys>();

就我个人而言,我是一个扩展方法的粉丝,所以我会使用这样的东西(虽然不是真正的扩展,但它看起来很相似):

public enum Options {
Zero,
One,
Two,
Three,
Four,
Five
}


public static class RandomEnum {
private static Random _Random = new Random(Environment.TickCount);


public static T Of<T>() {
if (!typeof(T).IsEnum)
throw new InvalidOperationException("Must use Enum type");


Array enumValues = Enum.GetValues(typeof(T));
return (T)enumValues.GetValue(_Random.Next(enumValues.Length));
}
}


[TestClass]
public class RandomTests {
[TestMethod]
public void TestMethod1() {
Options option;
for (int i = 0; i < 10; ++i) {
option = RandomEnum.Of<Options>();
Console.WriteLine(option);
}
}


}

下面是使用LINQ作为Extension Method的替代版本。

using System;
using System.Linq;


public static class EnumExtensions
{
public static Enum GetRandomEnumValue(this Type t)
{
return Enum.GetValues(t)          // get values from Type provided
.OfType<Enum>()               // casts to Enum
.OrderBy(e => Guid.NewGuid()) // mess with order of results
.FirstOrDefault();            // take first item in result
}
}


public static class Program
{
public enum SomeEnum
{
One = 1,
Two = 2,
Three = 3,
Four = 4
}


public static void Main()
{
for(int i=0; i < 10; i++)
{
Console.WriteLine(typeof(SomeEnum).GetRandomEnumValue());
}
}
}
< p > 2
一个




两个

一个

< / p >

你可以这样做:

var rnd = new Random();
return (MyEnum) rnd.Next(Enum.GetNames(typeof(MyEnum)).Length);

不需要存储数组

改编为随机类扩展:

public static class RandomExtensions
{
public static T NextEnum<T>(this Random random)
{
var values = Enum.GetValues(typeof(T));
return (T)values.GetValue(random.Next(values.Length));
}
}

用法示例:

var random = new Random();
var myEnumRandom = random.NextEnum<MyEnum>();

你也可以强制转换一个随机值:

using System;


enum Test {
Value1,
Value2,
Value3
}


class Program {
public static void Main (string[] args) {
var max = Enum.GetValues(typeof(Test)).Length;
var value = (Test)new Random().Next(0, max - 1);
Console.WriteLine(value);
}
}

但是你应该使用更好的随机函数发生器,就像我的这个图书馆中的那个。

很多答案都很老了,而且——如果我说错了请纠正我——似乎只涉及一些粗略的概念,比如类型擦除和动态类型转换。然而,正如用户Yarek T指出的那样,Enum.GetValues的泛型重载不需要这样做:

static Random random = new Random();


// Somewhat unintuitively, we need to constrain the type parameter to
// both struct *and* Enum - struct is required b/c the type can't be
// nullable, and Enum is required b/c GetValues expects an Enum type.
// You'd think that Enum itself would satisfy the non-nullable
// constraint, but alas, me compiler tells me otherwise - perhaps
// someone more knowledgeable can explain why this is in a comment?
static TEnum RandomEnumValue<TEnum>() where TEnum : struct, Enum
{
TEnum[] vals = Enum.GetValues<TEnum>();
return vals[random.Next(vals.Length)];
}

或者,像博尔哈·加西亚的回答一样,我们甚至可以把它写成随机类的扩展

public static class RandomExtensions
{
public static TEnum NextEnumValue<TEnum>(this Random random)
where TEnum : struct, Enum
{
TEnum[] vals = Enum.GetValues<TEnum>();
return vals[random.Next(vals.Length)];
}
}

我们可以从mafu的回答运行相同的测试:

Random random = new Random();
for (int i = 0; i < 10; i++) {
var day = random.NextEnumValue<System.DayOfWeek>();
Console.WriteLine(day.ToString());
}

潜在产出:

Thursday
Saturday
Sunday
Sunday
Sunday
Saturday
Wednesday
Monday
Wednesday
Thursday

结合这个答案它的评论的现代答案:

public static class RandomExtensions
{
private static Random Random = new Random();


public static T GetRandom<T>() where T : struct, Enum
{
T[]? v = Enum.GetValues<T>();
return (T)v.GetValue(Random.Next(v.Length));
}
}