Лучший способ получить все биты флага enum? - PullRequest
19 голосов
/ 12 августа 2010

У меня есть enum с атрибутом Flags.

Мой вопрос: я бы хотел получить целочисленную битовую маску для всех опций, не комбинируя вручную все биты.Я хочу сделать это, чтобы сравнить с некоторым другим полем int, и хочу защитить в случае, если будущий разработчик объявит больше битовых опций в enum.

Другое дело, что биты в моих флагах перечисления будут все вручнуюназначен, поэтому я не могу просто получить следующее значение и вычесть 1.

Ответы [ 5 ]

21 голосов
/ 12 августа 2010

Если я правильно понял, что вы спросили, это должно работать для вас:

Enum.GetValues(typeof(Enum)).Cast<int>().Sum();

Затем вы можете привести его обратно к вашему typeof(Enum):

[Flags]
public enum Values
{
    Value_1 = 1,
    Value_2 = 2,
    Value_3 = 4,
    Value_4 = 8,
    Value_5 = 16,
    Value_6 = 32,
    Value_7 = 64,
    Value_8 = 128,
    Value_9 = 256
}

static void Main(string[] args)
{
    Values values = (Values)Enum.GetValues(typeof(Values)).Cast<int>().Sum();
}

enter image description here

7 голосов
/ 12 августа 2010
// uses a ulong to handle all possible underlying types without error
var allFlags = Enum.GetValues(typeof(YourEnumType))
                   .Cast<YourEnumType>()
                   .Aggregate((YourEnumType)0, (a, x) => a | x, a => (ulong)a);
6 голосов
/ 12 августа 2010

Взгляните на мой Unconstrained Melody проект, который совершает злые вещи, позволяя создавать замечательные функции на общих методах, ограниченных перечислениями и делегатами.

В этом случае, я думаю, вы захотите позвонить Flags.GetUsedBits<YourEnumType>().

Если вы не возражаете против использования дополнительной (очень маленькой) библиотеки, я хотел бы подумать, что Unconstrained Melody делает жизнь приятнее при работе с флагами. Если у вас есть какие-либо пожелания, я бы с удовольствием посмотрел:)

4 голосов
/ 12 августа 2010

Вид сырой, но как-то так?

[Flags]
enum SomeFlags
{
    Flag1 = 1,
    Flag2 = 2,
    Flag3 = 4,
    Flag4 = 16,
    Flag5 = 32,
    Flag6 = 64
}

static void Main(string[] args)
{
    SomeFlags flags = 0;

    SomeFlags[] values = (SomeFlags[])Enum.GetValues(typeof(SomeFlags));
    Array.ForEach<SomeFlags>(values, delegate(SomeFlags v) { flags |= v; });

    int bitMask = Convert.ToInt32(flags);
}
0 голосов
/ 12 августа 2010

Вот способ сделать это, используя идеи из универсальных операторов , написанных Джоном Скитом и Марком Гравеллом:

void Main()
{
    Console.WriteLine(CombineAllFlags<MyEnum>()); // Prints "Foo, Bar, Baz"
}

[Flags]
public enum MyEnum
{
    Foo = 1,
    Bar = 2,
    Baz = 4
}

public static TEnum CombineAllFlags<TEnum>()
{
    TEnum[] values = (TEnum[])Enum.GetValues(typeof(TEnum));
    TEnum tmp = default(TEnum);
    foreach (TEnum v in values)
    {
        tmp = EnumHelper<TEnum>.Or(tmp, v);
    }
    return tmp;
}

static class EnumHelper<T>
{
    private static Func<T, T, T> _orOperator = MakeOrOperator();

    private static Func<T, T, T> MakeOrOperator()
    {
        Type underlyingType = Enum.GetUnderlyingType(typeof(T));
        ParameterExpression xParam = Expression.Parameter(typeof(T), "x");
        ParameterExpression yParam = Expression.Parameter(typeof(T), "y");
        var expr =
            Expression.Lambda<Func<T, T, T>>(
                Expression.Convert(
                    Expression.Or(
                        Expression.Convert(xParam, underlyingType),
                        Expression.Convert(yParam, underlyingType)),
                    typeof(T)),
                xParam,
                yParam);
        return expr.Compile();
    }

    public static T Or(T x, T y)
    {
        return _orOperator(x, y);
    }   
}

Этот код динамически создает делегат, который объединяет значения перечисления соператор ИЛИ

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...