6

Flags属性で装飾された列挙型を受け入れる関数があるとします。列挙型の値が複数の列挙型要素の組み合わせである場合、これらの要素の1つをランダムに抽出するにはどうすればよいですか?私は以下を持っていますが、もっと良い方法があるに違いないようです。

[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();
}
4

5 に答える 5

11

次のように、呼び出しEnum.GetValuesて列挙型の定義済み値の配列を取得できます。

var rand = new Random();

Colors[] allValues = (Colors[])Enum.GetValues(typeof(Colors));
Colors value = allValues[rand.Next(allValues.Length)];
于 2010-06-08T22:00:35.773 に答える
9
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)];
于 2010-06-09T00:20:54.010 に答える
2

私が正しく理解していれば、問題はフラグ列挙型からランダムなメンバーを返すことではなく、フラグ列挙型値からランダムな列挙値を返すことです。

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

編集

簡略化

于 2010-06-08T22:28:18.147 に答える
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)));
于 2010-06-08T22:44:56.290 に答える
0

私の場合-たとえば、メンバーが欠落している列挙型と、最大値を持つ0x01, 0x02, 0x08大きなulong列挙型があります。0x200000000

このコードは私のすべての場合に機能します:

/// <summary>
///     Gets <see cref="System.Random"/> instance.
/// </summary>
public static Random Random { get; } = new Random(Guid.NewGuid().GetHashCode());

/// <summary>
///     Gets random combination of Flags Enum.
/// </summary>
/// <typeparam name="T">Enum type.</typeparam>
/// <returns>Random Flags Enum combination.</returns>
public static T GetRandomFlagsEnumValue<T>()
    where T : Enum
{
    var allValues = (T[])Enum.GetValues(typeof(T));

    ulong numberValue = allValues.OrderBy(x => Random.Next())
        .Take(GetRandomInteger(1, allValues.Length - 1))
        .Select(e => Convert.ToUInt64(e, CultureInfo.InvariantCulture))
        .Aggregate((a, c) => a + c);

    return (T)Enum.ToObject(typeof(T), numberValue);
}
于 2020-02-19T14:00:46.927 に答える