2010-06-28 3 views
125

Dato un enumerazione arbitraria in C#, come posso selezionare un valore casuale?Come si seleziona un valore casuale da un'enumerazione?

(non ho trovato questa domanda molto di base su SO. Vi posterò la mia risposta in un minuto come riferimento per chiunque, ma non esitate a inviare la propria risposta.)

risposta

209
Array values = Enum.GetValues(typeof(Bar)); 
Random random = new Random(); 
Bar randomBar = (Bar)values.GetValue(random.Next(values.Length)); 
+28

Assicurarsi di non tenere ricreare 'random' in un loop stretto anche se - altrimenti ti continuo a ricevere lo stesso valore. – ChrisF

+0

Deve essere casuale. Successivo (valori.Lunghezza -1)? – uriDium

+3

@uriDium No, l'argomento specifica quale valore è il primo a essere troppo grande per essere restituito (ad es._max meno 1_) – mafu

47

Utilizzare Enum.GetValues ​​a recuperare una matrice di tutti i valori. Quindi seleziona un elemento dell'array casuale.

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

prova:

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 

Aggiornamento: Questa risposta originariamente utilizzato OrderBy (x => _Random.Next()).FirstOrDefault() per selezionare un elemento casuale. Usalo solo se sei irrazionalmente attratto dal mischiare con chiavi casuali. In ogni altro caso, usa invece la risposta accettata da Darin Dimitrov, che ho incorporato in questa risposta più tardi.

2

Chiama Enum.GetValues; questo restituisce un array che rappresenta tutti i valori possibili per il tuo enum. Scegli un oggetto a caso da questo array. Trasmetti l'oggetto al tipo originale enum.

2

Ecco una funzione generica per questo. Mantenere la creazione di RNG al di fuori del codice di alta frequenza. esempio

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

Usage:

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

Avere un metodo statico che non è protetto da thread è piuttosto pericoloso. – CodesInChaos

+0

@CodesInChaos Hai ragione. Random.Next() non è thread-safe e inizierà a restituire zero quando si interrompe. Ho aggiornato la mia risposta in base a queste informazioni. – WHol

0

Personalmente, io sono un fan di metodi di estensione, quindi vorrei usare qualcosa come questo (mentre in realtà non un'estensione, sembra simile):

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

} 
0

Ecco una versione alternativa come Extension Method utilizzando LINQ.

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

Due
Uno
Quattro
Quattro
Quattro
Tre
Due
Quattro
Uno
Tre

1

Si potrebbe semplicemente fare questo:

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

Non c'è bisogno di memorizzare le matrici

+0

'GetNames' restituisce una matrice. –

+0

Intendevo dire che non è necessario memorizzarlo. Colpa mia –