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.)

Respostas:


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

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

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


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


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.


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

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

}

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

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 .

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.