Bagaimana cara memilih nilai acak dari enumerasi?

170

Diberikan penghitungan sewenang-wenang dalam C #, bagaimana cara memilih nilai acak?

(Saya tidak menemukan pertanyaan yang sangat mendasar ini di SO. Saya akan mengirimkan jawaban saya sebentar lagi sebagai referensi untuk siapa pun, tapi jangan ragu untuk mengirim jawaban Anda sendiri.)

mafu
sumber

Jawaban:

282
Array values = Enum.GetValues(typeof(Bar));
Random random = new Random();
Bar randomBar = (Bar)values.GetValue(random.Next(values.Length));
Darin Dimitrov
sumber
40
Pastikan Anda tidak terus membuat ulang randomdalam loop ketat - jika tidak, Anda akan tetap mendapatkan nilai yang sama.
ChrisF
1
Haruskah itu acak. Berikutnya (nilai. Panjang -1)?
uriDium
7
@uriDium Tidak, argumen menentukan nilai mana yang pertama terlalu besar untuk dikembalikan (yaitu maks. minus 1 )
mafu
values.Panjang - 1
Bojidar Stanchev
DarinDimitrov IMO komentar pertama oleh @ChrisF harus menjadi catatan di dalam jawaban dengan pujian untuk Chris.
maytham-ɯɐɥʇʎɐɯ
60

Gunakan Enum.GetValues ​​untuk mengambil larik semua nilai. Kemudian pilih item array acak.

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

Uji:

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

Anda bisa melakukan ini:

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

Tidak perlu menyimpan array

Breno Angelotti
sumber
GetNamesmengembalikan array.
Nathan Tuggy
Maksud saya, Anda tidak perlu menyimpannya. Buruk saya
Breno Angelotti
Jika seseorang melakukan ini dalam satu lingkaran, mereka akan memanggil GetNames setiap kali alih-alih menyimpannya dalam sebuah array. Ini akan memperlambat kode mereka jadi saya tidak melihat apa kontribusi Anda di sini?
Bojidar Stanchev
@BojidarStanchev JIKA , dalam kasus saya ini bekerja dengan baik, terima kasih Breno :)
Jaacko Torus
3

Inilah versi alternatif sebagai Extension Methodpenggunaan 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());
        }
    }           
}

Dua
Satu
Empat
Empat
Empat
Tiga
Dua
Empat
Satu
Tiga

Aaron Hudon
sumber
2

Panggilan Enum.GetValues; ini mengembalikan array yang mewakili semua nilai yang mungkin untuk enum Anda. Pilih item acak dari array ini. Keluarkan item itu kembali ke tipe enum asli.

Tim Robinson
sumber
2

Ini adalah fungsi generik untuk itu. Simpan ciptaan RNG di luar kode frekuensi tinggi.

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

Contoh penggunaan:

System.Windows.Forms.Keys randomKey = RandomEnum<System.Windows.Forms.Keys>();
Seluruh
sumber
Memiliki metode statis yang bukan threadsafe cukup berbahaya.
CodesInChaos
@CodesInChaos Anda benar. Random.Next () bukan threadsafe dan akan mulai mengembalikan nol saat rusak. Saya telah memperbarui jawaban saya berdasarkan info ini.
WHol
1

Secara pribadi, saya penggemar metode ekstensi, jadi saya akan menggunakan sesuatu seperti ini (walaupun bukan benar-benar ekstensi, tampilannya mirip):

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
sumber
1
Pada C # 7.3 Anda dapat membatasi tipe generik Anda menjadi enum: public static T Of<T>() where T : Enum docs.microsoft.com/en-us/visualstudio/releasenotes/…
nitzel
0

Diadaptasi sebagai ekstensi kelas acak:

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

Contoh penggunaan:

var random = new Random();
var myEnumRandom = random.NextEnum<MyEnum>();
borja garcia
sumber
0

Anda juga dapat memberikan nilai acak:

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

Tetapi Anda harus menggunakan pengacak yang lebih baik seperti yang ada di perpustakaan saya ini.

gsscoder
sumber