Подтвердить что ты не робот

Как проверить, установлено ли более одного флага enum?

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

[Flags]
enum Foo
{
Flag1 = 0x01,
Flag2 = 0x02,
Flag3 = 0x04,
Flag4 = 0x08,
Flag5 = 0x10,
Flag6 = 0x20,
Flag7 = 0x40,
Flag8 = 0x80
}

private bool ExactlynOneFlagSet(Foo myFoo)
{
  var x = (byte) myFoo;
  return (x != 0) && ((x & (x - 1)) == 0); //Check if a power of 2
}

if(!ExactlynOneFlagSet(Foo myFoo))
{
   //Do something
}
4b9b3361

Ответ 1

Его бит операция!

if ((myFoo & (myFoo -1)) != 0) //has more than 1 flag

Оператор проверяет, не является ли значение myFoo не равным двум. Или, наоборот, утверждение (myFoo & (myFoo -1)) == 0 проверяет силу двух. Идея состоит в том, что только значения одного флага будут иметь силу двух. Установка более одного флага приведет к недействительности двух значений myFoo.

Более подробную информацию можно найти в этом ответе на аналогичный вопрос: fooobar.com/questions/174515/....

Для получения дополнительной информации о битовых операциях перейдите в http://en.wikipedia.org/wiki/Bitwise_operation

Ответ 2

private bool ExatlyOneFlagSet(Foo myFoo)
{
  return !myFoo.ToString().Contains(',');
}

Ответ 3

Если перечисление не определяет явные комбинации флагов, вы можете просто проверить, определено ли значение в перечислении:

private bool ExactlynOneFlagSet(Foo myFoo)
{
    return Enum.IsDefined(typeof(Foo), myFoo);
}

Ответ 4

Как пояснил Джейкоб в комментарии, ваш метод не совсем прав. Лично я всегда избегаю программирования математически, особенно когда дело доходит до логики. Таким образом, мое решение было бы чем-то вроде "если бы я хотел знать, что счет один, поэтому считайте его и сравните его с номером один".

Вот он:

    public static bool OneIsSet(Type enumType, byte value)
    {
        return Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == 1;
    }

    public static bool OneIsSet(Type enumType, int value)
    {
        return Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == 1;
    }

И вы можете использовать его для своего типа foo следующим образом:

   var toReturnFalse = (byte)(foo.Flag1 | foo.Flag2);
   var toReturnTrue = (byte)foo.Flag1;
   var trueWillBeReturned = OneIsSet(typeof(foo), toReturnTrue);
   var falseWillBeReturned = OneIsSet(typeof(foo), toReturnFalse);

Я считаю, что эти методы могут быть написаны более общим способом с использованием методов обработки данных Generics и type. Однако я включил методы для большинства распространенных базовых типов для перечислений, которые являются int и байтом. Но вы также можете написать то же самое для коротких и других типов. Также вы можете просто вставить код в свой код. Это только одна строка кода.

Также используя этот метод, вы можете увидеть, есть ли количество установленных флагов два или более. Код ниже возвращает true, если количество установленных флагов равно "n".

   Enum.GetValues(enumType).Cast<byte>().Count(v => (value & v) == v) == n;