tags:

views:

2330

answers:

4

Could someone please point me toward a cleaner method to generate a random enum member. This works but seems ugly.

Thanks!

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);
}
+12  A: 
public T RandomEnum<T>()
{ 
  T[] values = (T[]) Enum.GetValues(typeof(T));
  return values[new Random().Next(0,values.Length)];
}

Thanks to @[Marc Gravell] for ponting out that the max in Random.Next(min,max) is exclusive.

Mark Cidade
Thanks - mine was killing me!
Of course in a real implementation you would not want to use a new Random every call (especially if you call it often) and I personally would want to cache the array.
Dolphin
+8  A: 

Marxidad's answer is good (note you only need Next(0,values.Length), since the upper bound is exclusive) - but watch out for timing. If you do this in a tight loop, you will get lots of repeats. To make it more random, consider keeping the Random object in a field - i.e.

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

If it is a static field, you will need to synchronize access.

Marc Gravell
In my case it's just generating some defaults for a game - no loops at all. Thanks for the advice!
A: 

I'm not sure about c# but other languages allow gaps in enum values. To account for that:

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;
}

The major down side is keeping it up to date!

Not near as neat but more correct in that corner case.


As pointed out, the examples from above index into an array of valid values and this get it right. OTOH some languages (cough D cough) don't provide that array so the above is useful enough that I'll leave it anyway.

BCS
marxidad accounts for this by returning an array index not the enum's value. I did the same I just took the scenic route!
That could have clearer. The enum is generated by its position in the array not by its value.
A: 

Silverlight does not have GetValues(), but you can use reflection to get a random enum instead.

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);
}
pixie