24

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

5 Answers 5

43
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.

Sign up to request clarification or add additional context in comments.

3 Comments

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.
Note that Silverlight doesn't have Enum.GetValues. See alternate solution further down.
BEWARE This answer is flawed. As it was said before if the generation is tight together this will result in no randomness at all.
15

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.

1 Comment

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

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

Comments

0

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.

2 Comments

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.
0
Enum.Parse(typeof(SomeEnum), mRandom.Next(min, max).ToString()).ToString()

1 Comment

This method doesn't work if there are gaps between the numeric values of the Enum Values (and that is quite possible to happen).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.