2010-06-08 7 views
5

Dites que j'ai une fonction qui accepte une énumération décorée avec l'attribut Flags. Si la valeur de l'enum est une combinaison de plus d'un des éléments enum, comment puis-je extraire un de ces éléments au hasard? J'ai ce qui suit mais il semble qu'il doit y avoir un meilleur moyen.Valeur aléatoire de Flags enum

[Flags] 
enum Colours 
{ 
    Blue = 1, 
    Red = 2, 
    Green = 4 
} 

public static void Main() 
{ 
    var options = Colours.Blue | Colours.Red | Colours.Green; 
    var opts = options.ToString().Split(','); 
    var rand = new Random(); 
    var selected = opts[rand.Next(opts.Length)].Trim(); 
    var myEnum = Enum.Parse(typeof(Colours), selected); 
    Console.WriteLine(myEnum); 
    Console.ReadLine(); 
} 

Répondre

8
var options = Colours.Blue | Colours.Green; 

var matching = Enum.GetValues(typeof(Colours)) 
        .Cast<Colours>() 
        .Where(c => (options & c) == c) // or use HasFlag in .NET4 
        .ToArray(); 

var myEnum = matching[new Random().Next(matching.Length)]; 
9

Vous pouvez appeler Enum.GetValues pour obtenir un tableau des valeurs définies de l'ENUM, comme ceci:

var rand = new Random(); 

Colors[] allValues = (Colors[])Enum.GetValues(typeof(Colors)); 
Colors value = allValues[rand.Next(allValues.Length)]; 
+0

Je voudrais une valeur aléatoire de seulement un sous-ensemble de l'ENUM tel que défini par un combinaison bit à bit comme "Blue | Red". Désolé de ne pas être plus clair. –

1

Si je comprends bien, la question est de retourner une valeur ENUM au hasard à partir d'un drapeau de valeur ENUM , ne retourne pas un membre aléatoire d'une énumération de drapeaux.

[Flags] 
    private enum Shot 
    { 
     Whisky = 1, 
     Absynthe = 2, 
     Pochin = 4, 
     BrainEraser = Whisky | Absynthe | Pochin 
    } 

    [Test] 
    public void Test() 
    { 
     Shot myCocktail = Shot.Absynthe | Shot.Whisky; 

     Shot randomShotInCocktail = GetRandomShotFromCocktail(myCocktail); 
    } 

    private static Shot GetRandomShotFromCocktail(Shot cocktail) 
    { 
     Random random = new Random(); 

     Shot[] cocktailShots = Enum.GetValues(typeof(Shot)). 
      Cast<Shot>(). 
      Where(x => cocktail.HasFlag(x)).ToArray(); 

     Shot randomShot = cocktailShots[random.Next(0, cocktailShots.Length)]; 

     return randomShot; 
    } 

Modifier

Et évidemment, vous devriez vérifier que le ENUM est une valeur valide, .: par exemple

Shot myCocktail = (Shot)666; 

Modifier

simplifié

+1

Vous avez raison d'énoncer le problème. Cependant, je pense que votre fonction aléatoire ne retournera pas les valeurs avec une distribution égale. À une chance 50/50 pour chaque valeur à travers la boucle les valeurs suivantes ont une plus faible chance d'être sélectionné? –

+0

Je vois ce que vous voulez dire. Strictement parlant, il est encore aléatoire et répond à votre question. Je l'ai mis à jour à une distribution même. Il est tard et je suis sûr que j'ai probablement bourré! :) –

+0

Et maintenant simplifié. –

2

I Si cela ne vous dérange pas un peu de lancer, et votre énumération est de type int sous-jacente, ce qui suit va fonctionner et est rapide.

var rand = new Random(); 
const int mask = (int)(Colours.Blue | Colours.Red | Colours.Green); 
return (Colours)(mask & (rand.Next(mask) + 1)); 

Si vous voulez un seul drapeau à régler, vous pouvez effectuer les opérations suivantes:

var rand = new Random(); 
return (Colours)(0x1 << (rand.Next(3))); 
+0

Si le résultat de "(int) allValues ​​& rand.Next()" est zéro, et vous n'avez pas de zéro membre enum, vous obtenez un enum ie (Colors) 0 invalide. –

+0

True. Laissez-moi voir si cela peut être corrigé ... – bbudge

+0

OK, je pense que ça marche maintenant. Mais ça devient un peu plus compliqué et moins clair. Seulement utile si la performance est une préoccupation sérieuse. – bbudge