Comment sélectionner une valeur aléatoire dans une énumération?

172

Étant donné une énumération arbitraire en C #, comment sélectionner une valeur aléatoire?

(Je n'ai pas trouvé cette question très basique sur SO. Je publierai ma réponse dans une minute comme référence pour tout le monde, mais n'hésitez pas à poster votre propre réponse.)

mafu
la source

Réponses:

283
Array values = Enum.GetValues(typeof(Bar));
Random random = new Random();
Bar randomBar = (Bar)values.GetValue(random.Next(values.Length));
Darin Dimitrov
la source
40
Assurez-vous de ne pas continuer à recréer randomen boucle, sinon vous continuerez à obtenir la même valeur.
ChrisF
1
Cela devrait-il être aléatoire.Next (values.Length -1)?
uriDium
7
@uriDium Non, l'argument spécifie quelle valeur est la première à être trop grande pour être renvoyée (c'est-à-dire max moins 1 )
mafu
valeurs Longueur - 1
Bojidar Stanchev
DarinDimitrov IMO le premier commentaire de @ChrisF devrait être une note à l'intérieur de la réponse avec crédit à Chris.
maytham-ɯɐɥʇʎɐɯ
62

Utilisez Enum.GetValues ​​pour récupérer un tableau de toutes les valeurs. Sélectionnez ensuite un élément de tableau aléatoire.

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

Tester:

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
mafu
la source
5

Vous pouvez simplement faire ceci:

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

Pas besoin de stocker des tableaux

Breno Angelotti
la source
GetNamesrenvoie un tableau.
Nathan Tuggy
Je voulais dire que vous n'avez pas besoin de le stocker. My bad
Breno Angelotti
Si quelqu'un fait cela dans une boucle, il appellerait GetNames à chaque fois au lieu de le mettre en cache dans un tableau. Cela ralentirait leur code et je ne vois pas quelle est votre contribution ici?
Bojidar Stanchev
@BojidarStanchev IF , dans mon cas, cela fonctionne à merveille, merci Breno :)
Jaacko Torus
4

Voici une version alternative comme Extension Methodutilisation 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());
        }
    }           
}

Deux
un
quatre
quatre
quatre
trois
deux
quatre
un
trois

Aaron Hudon
la source
2

Appel Enum.GetValues; cela renvoie un tableau qui représente toutes les valeurs possibles pour votre énumération. Choisissez un élément au hasard dans ce tableau. Cast cet élément vers le type d'énumération d'origine.

Tim Robinson
la source
2

Voici une fonction générique pour cela. Gardez la création RNG en dehors du code haute fréquence.

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

Exemple d'utilisation:

System.Windows.Forms.Keys randomKey = RandomEnum<System.Windows.Forms.Keys>();
WHol
la source
Avoir une méthode statique qui n'est pas threadsafe est assez dangereux.
CodesInChaos
@CodesInChaos Vous avez raison. Random.Next () n'est pas threadsafe et commencera à renvoyer des zéros quand il se cassera. J'ai mis à jour ma réponse en fonction de ces informations.
WHol
1

Personnellement, je suis un fan des méthodes d'extension, donc j'utiliserais quelque chose comme ça (bien que ce ne soit pas vraiment une extension, cela a l'air similaire):

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

}
Champagne Dan
la source
1
À partir de C # 7.3, vous pouvez contraindre votre type générique à être une énumération: public static T Of<T>() where T : Enum docs.microsoft.com/en-us/visualstudio/releasenotes/…
nitzel
0

Adapté comme une extension de classe aléatoire:

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

Exemple d'utilisation:

var random = new Random();
var myEnumRandom = random.NextEnum<MyEnum>();
Borja Garcia
la source
0

Vous pouvez également lancer une valeur aléatoire:

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

Mais vous devriez utiliser un meilleur randomiseur comme celui de cette bibliothèque .

gsscoder
la source