2010-06-08 55 views
5

說我有一個函數接受一個用Flags屬性裝飾的枚舉。如果枚舉的值是多個枚舉元素的組合,我如何隨機提取其中一個元素?我有以下,但似乎必須有更好的方法。來自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(); 
} 

回答

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

您可以撥打Enum.GetValues得到枚舉的定義值的數組,像這樣:

var rand = new Random(); 

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

我想通過一個定義僅枚舉的一個子集的隨機值按位組合,如「藍色|紅色」。對不起,不清楚。 – 2010-06-09 00:07:23

1

如果我理解正確的,問題是有關從標誌枚舉值返回一個隨機枚舉值,不會從flags枚舉中返回一個隨機成員。

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

編輯

而且很明顯,你應該檢查枚舉是一個有效的值,例如:

Shot myCocktail = (Shot)666; 

編輯

簡體

+1

您在說明問題時是正確的。不過,我認爲你的隨機函數不會返回具有均勻分佈的值。在循環中,每個值有50/50的機會,後續值的選擇機會較低? – 2010-06-09 00:01:25

+0

我明白你的觀點。嚴格來說,它仍然是隨機的,並回答你的問題。我已經更新到一個平均發行版。已經很晚了,我確信我可能已經塞滿了! :) – 2010-06-09 00:11:08

+0

現在簡化。 – 2010-06-09 00:26:19

2

我如果你不介意一點點投射,並且你的枚舉是基礎int類型的,下面的工作將會很快並且很快。

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

如果你只想要一個標誌設置,你可以做到以下幾點:

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

如果「(int)allValues&rand.Next()」的結果爲零,並且沒有零枚舉成員,你會得到一個無效的枚舉,即(顏色)0。 – 2010-06-08 22:53:49

+0

是的。讓我看看它是否可以修復... – bbudge 2010-06-08 23:10:43

+0

好吧,我認爲它現在可以工作。但它有點混亂,不太清楚。只有在性能是一個嚴重的問題時纔有用。 – bbudge 2010-06-08 23:32:45