2010-06-08 22 views
5

Angenommen, ich habe eine Funktion, die eine mit dem Flags-Attribut versehene Aufzählung akzeptiert. Wenn der Wert der Enumeration eine Kombination aus mehr als einem der Enumerationselemente ist, wie kann ich eines dieser Elemente zufällig extrahieren? Ich habe das Folgende, aber es scheint, dass es einen besseren Weg geben muss.Zufälliger Wert von 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(); 
} 

Antwort

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

Sie können Enum.GetValues nennen eine Reihe von ENUM die definierten Werte zu erhalten, wie folgt aus:

var rand = new Random(); 

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

ich einen zufälligen Wert von nur einer Teilmenge der ENUM durch eine definierte möchten bitweise Kombination wie "Blau | Rot". Tut mir leid, dass ich nicht klarer bin. –

1

Wenn ich richtig verstehe, ist die Frage über einen zufälligen Enum-Wert von einem Flags Enum-Wert Rückkehr , kein zufälliges Mitglied von einem Flags-Enum zurückgegeben.

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

bearbeiten

Und natürlich sollten Sie prüfen, ob der Enum ein gültiger Wert ist, z.B .:

Shot myCocktail = (Shot)666; 

bearbeiten

Simplified

+1

Sie haben das Problem richtig angegeben. Ich denke jedoch, dass Ihre Zufallsfunktion die Werte nicht mit einer gleichmäßigen Verteilung zurückgibt. Bei einer 50/50-Chance für jeden Wert durch die Schleife haben nachfolgende Werte eine geringere Chance ausgewählt zu werden? –

+0

Ich sehe deinen Standpunkt. Streng genommen ist es noch zufällig und beantwortet Ihre Frage. Ich habe es auf eine gerade Distribution aktualisiert. Es ist spät und ich bin mir sicher, dass ich wahrscheinlich gestopft habe! :) –

+0

Und jetzt vereinfacht. –

2

I Wenn es Ihnen nichts ausmacht, ein kleines Casting zu machen, und Ihr Enum ist von int. Typ, das folgende wird funktionieren und ist schnell.

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

Wenn Sie nur ein einziges Flag gesetzt werden möchten, können Sie wie folgt vorgehen:

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

Wenn das Ergebnis von "(int) allValues ​​& rand.Next()" ist Null, und Sie haben keine Null Aufzählungselement, Sie erhalten eine ungültige enum ie (Farben) 0. –

+0

Wahr. Lass mich sehen ob es behoben werden kann ... – bbudge

+0

OK, ich denke es klappt jetzt. Aber es wurde etwas unordentlicher und weniger klar. Nur nützlich, wenn Leistung ein ernsthaftes Problem darstellt. – bbudge