Como seleciono um valor aleatório de uma enumeração?

170

Dada uma enumeração arbitrária em C #, como faço para selecionar um valor aleatório?

(Não encontrei esta pergunta muito básica no SO. Vou postar minha resposta em um minuto como referência para qualquer pessoa, mas fique à vontade para postar sua própria resposta.)

mafu
fonte

Respostas:

282
Array values = Enum.GetValues(typeof(Bar));
Random random = new Random();
Bar randomBar = (Bar)values.GetValue(random.Next(values.Length));
Darin Dimitrov
fonte
40
Certifique-se de não continuar recriando randomem um circuito fechado - caso contrário, você continuará recebendo o mesmo valor.
ChrisF
1
Isso deve ser aleatório.Próximo (values.Length -1)?
uridium
7
@uriDium Não, especifica argumento que valor é o primeiro a ser demasiado grande para ser devolvido (ou seja, menos max 1 )
Mafu
values.Length - 1
Bojidar Stanchev
DarinDimitrov IMO, o primeiro comentário de @ChrisF deve ser uma nota dentro da resposta com crédito a Chris.
maytham-ɯɐɥʇʎɐɯ
60

Use Enum.GetValues ​​para recuperar uma matriz de todos os valores. Em seguida, selecione um item de matriz aleatória.

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

Teste:

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

Você poderia fazer isso:

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

Não há necessidade de armazenar matrizes

Breno Angelotti
fonte
GetNamesretorna uma matriz.
Nathan Tuggy
Eu quis dizer que você não precisa armazená-lo. Meu mal
Breno Angelotti
Se alguém estiver fazendo isso em um loop, chamará GetNames toda vez, em vez de armazená-lo em cache em uma matriz. Isso atrasaria o código, então não vejo qual é a sua contribuição aqui?
Bojidar Stanchev 10/10/19
@BojidarStanchev SE , no meu caso, isso funciona maravilhoso, obrigado Breno :)
Jaacko Torus 01/02
3

Aqui está uma versão alternativa como uma Extension Methodutilização 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());
        }
    }           
}

Dois
um
quatro
quatro
quatro
três
dois
quatro
um
três

Aaron Hudon
fonte
2

Chamada Enum.GetValues; isso retorna uma matriz que representa todos os valores possíveis para sua enumeração. Escolha um item aleatório dessa matriz. Lance esse item de volta ao tipo de enumeração original.

Tim Robinson
fonte
2

Aqui está uma função genérica para isso. Mantenha a criação do RNG fora do código de alta frequência.

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

Exemplo de uso:

System.Windows.Forms.Keys randomKey = RandomEnum<System.Windows.Forms.Keys>();
WHol
fonte
Ter um método estático que não é seguro para threads é bastante perigoso.
CodesInChaos 30/07/2015
@CodesInChaos Você está certo. Random.Next () não é seguro para threads e começará a retornar zeros quando quebrar. Atualizei minha resposta com base nessas informações.
May
1

Pessoalmente, sou fã de métodos de extensão, então usaria algo assim (embora não seja realmente uma extensão, é semelhante):

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
fonte
1
A partir de C # 7.3 você pode constrangimento seu tipo genérico para ser um enum: public static T Of<T>() where T : Enum docs.microsoft.com/en-us/visualstudio/releasenotes/...
nitzel
0

Adaptado como uma extensão de classe aleatória:

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

Exemplo de uso:

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

Você também pode converter um valor aleatório:

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

Mas você deve usar um randomizador melhor como o desta minha biblioteca .

gsscoder
fonte