在C# 2.0中生成随机枚举

24

请问是否有更简洁的方法来生成随机枚举成员?下面的方法可以实现,但看起来不够优雅。

谢谢!

public T RandomEnum<T>()
{
  string[] items = Enum.GetNames(typeof( T ));
  Random r = new Random();
  string e = items[r.Next(0, items.Length - 1)];
  return (T)Enum.Parse(typeof (T), e, true);
}
5个回答

43
public T RandomEnum<T>()
{ 
  T[] values = (T[]) Enum.GetValues(typeof(T));
  return values[new Random().Next(0,values.Length)];
}

感谢@[Marc Gravell]指出Random.Next(min,max)中的max是不包括在内的。


3
在实际的实现中,你不想在每次调用时都使用一个新的 Random(尤其是如果你经常调用它),我个人会想要缓存该数组。 - Dolphin
1
请注意,Silverlight没有Enum.GetValues。请参见下面的替代解决方案。 - Frode Lillerud
2
注意,这个答案是有缺陷的。正如之前所说,如果生成在一起太紧密,这将导致完全没有随机性。 - Luis

15

Marxidad的回答很好(请注意,你只需要Next(0,values.Length),因为上限是排除在外的)- 但要注意时间。如果你在紧密的循环中这样做,你会得到很多重复的结果。为了使其更随机,请考虑将Random对象保存在一个字段中,即:

private Random rand = new Random();
public T RandomEnum<T>()
{ 
  T[] values = (T[]) Enum.GetValues(typeof(T));
  return values[rand.Next(0,values.Length)];
}

如果是静态字段,您需要同步访问。

在我的情况下,这只是为游戏生成一些默认值 - 没有任何循环。感谢您的建议! - user10178

3
Silverlight没有GetValues()方法,但是您可以使用反射来获取一个随机的枚举值。
private Random rnd = new Random();

public T RndEnum<T>()
{
    FieldInfo[] fields = typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public);

    int index = rnd.Next(fields.Length);

    return (T) Enum.Parse(typeof(T), fields[index].Name, false);
}

谢谢,我需要这个用于Silverlight! - Frode Lillerud

0

我不确定C#是否允许枚举值之间存在间隔,但其他编程语言是允许的。为了考虑到这一点:

enum A {b=0,c=2,d=3,e=42};

switch(rand.Next(0,4))
{
   case 0: return A.b;
   case 1: return A.c;
   case 2: return A.d;
   case 3: return A.e;
}

主要的缺点是保持它的最新状态!

不太整洁,但在那个角落的情况下更正确。


正如所指出的那样,上面的示例将索引到有效值数组中,并且这样做是正确的。然而,一些语言(咳咳D咳咳)没有提供该数组,因此即使如此,上述代码仍然很有用。

marxidad 通过返回数组索引而不是枚举值来解决了这个问题。我也是这样做的,只是走了一条风景线! - user10178
这可能需要更清晰明了。枚举是由其在数组中的位置而非其值生成的。 - user10178

0
Enum.Parse(typeof(SomeEnum), mRandom.Next(min, max).ToString()).ToString()

如果枚举值之间存在数字上的间隔(这种情况很可能发生),那么该方法将无法正常工作。 - Styxxy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接