Wie wähle ich einen zufälligen Wert aus einer Aufzählung aus?

170

Wie wähle ich bei einer beliebigen Aufzählung in C # einen zufälligen Wert aus?

(Ich habe diese sehr grundlegende Frage auf SO nicht gefunden. Ich werde meine Antwort in einer Minute als Referenz für jeden veröffentlichen, aber Sie können gerne Ihre eigene Antwort veröffentlichen.)

Mafu
quelle

Antworten:

282
Array values = Enum.GetValues(typeof(Bar));
Random random = new Random();
Bar randomBar = (Bar)values.GetValue(random.Next(values.Length));
Darin Dimitrov
quelle
40
Stellen Sie jedoch sicher, dass Sie nicht randomin einer engen Schleife neu erstellen - andernfalls erhalten Sie immer den gleichen Wert.
ChrisF
1
Sollte das zufällig sein.Nächste (Werte.Länge -1)?
UriDium
7
@uriDium Nein, das Argument gibt an, welcher Wert der erste ist, der zu groß ist, um zurückgegeben zu werden (dh max minus 1 )
mafu
Werte.Länge - 1
Bojidar Stanchev
DarinDimitrov IMO Der erste Kommentar von @ChrisF sollte eine Notiz in der Antwort sein, die Chris zu verdanken ist.
Maytham - 21.
60

Verwenden Sie Enum.GetValues, um ein Array aller Werte abzurufen. Wählen Sie dann ein zufälliges Array-Element aus.

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

Prüfung:

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
quelle
5

Sie könnten dies einfach tun:

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

Arrays müssen nicht gespeichert werden

Breno Angelotti
quelle
GetNamesgibt ein Array zurück.
Nathan Tuggy
Ich meinte, dass Sie es nicht speichern müssen. Mein schlechtes
Breno Angelotti
Wenn jemand dies in einer Schleife tut, ruft er jedes Mal GetNames auf, anstatt es in einem Array zwischenzuspeichern. Dies würde ihren Code verlangsamen, so dass ich nicht sehe, was Ihr Beitrag hier ist?
Bojidar Stanchev
@BojidarStanchev WENN , in meinem Fall funktioniert das wunderbar, danke Breno :)
Jaacko Torus
3

Hier ist eine alternative Version als Extension MethodVerwendung 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());
        }
    }           
}

Zwei
Eins
Vier
Vier
Vier
Drei
Zwei
Vier Vier
Eins
Drei

Aaron Hudon
quelle
2

Rufen Sie an Enum.GetValues; Dies gibt ein Array zurück, das alle möglichen Werte für Ihre Aufzählung darstellt. Wählen Sie ein zufälliges Element aus diesem Array. Wirf diesen Gegenstand auf den ursprünglichen Aufzählungstyp zurück.

Tim Robinson
quelle
2

Hier ist eine generische Funktion dafür. Halten Sie die RNG-Erstellung außerhalb des Hochfrequenzcodes.

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

Anwendungsbeispiel:

System.Windows.Forms.Keys randomKey = RandomEnum<System.Windows.Forms.Keys>();
WHol
quelle
Eine statische Methode zu haben, die nicht threadsicher ist, ist ziemlich gefährlich.
CodesInChaos
@CodesInChaos Du hast recht. Random.Next () ist nicht threadsicher und gibt Nullen zurück, wenn es bricht. Ich habe meine Antwort basierend auf diesen Informationen aktualisiert.
Ganz
1

Persönlich bin ich ein Fan von Erweiterungsmethoden, daher würde ich so etwas verwenden (obwohl es nicht wirklich eine Erweiterung ist, sieht es ähnlich aus):

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

}
Dan Champagne
quelle
1
Ab C # 7.3 können Sie Ihren generischen Typ auf eine Aufzählung beschränken: public static T Of<T>() where T : Enum docs.microsoft.com/en-us/visualstudio/releasenotes/…
nitzel
0

Angepasst als zufällige Klassenerweiterung:

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

Anwendungsbeispiel:

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

Sie können auch einen zufälligen Wert umwandeln:

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

Aber Sie sollten einen besseren Randomizer wie den in meiner Bibliothek verwenden .

gsscoder
quelle