Есть ли другой способ проверить битовые поля Enum? - PullRequest
10 голосов
/ 17 сентября 2010

При использовании Enums с битовыми полями:

   enum  ReallyBigEnum  { FirstChoice = 0x01, AnotherOption = 0x02 }
   ReallyBigEnum  flag = ReallyBigEnum.FirstChoice | ReallyBigEnum.AnotherOption;

код, используемый для проверки битов:

   if( (flag & ReallyBigEnum.AnotherOption) == ReallyBigEnum.AnotherOption ) { ... }

, который кажется многословным и подверженным ошибкам из-за необходимости повторять бит проходит испытания.

Было бы неплохо, если бы был какой-то способ сказать:

   if( flag.IsSet( ReallyBigEnum.AnotherOption ) ) { ... }

но Enums не поддерживает методы экземпляра. Итак, я попробовал шаблонную функцию:

   class Enums
   {
      public static bool IsSet<T>( T flag, T bit ) { return (flag & bit) == bit; }
   }

но код для проверки битов выглядит так:

   if( Enums.IsSet<ReallyBigEnum>( flag, ReallyBigEnum.AnotherOption ) ) { ... }

что много писать. Тогда я попытался сократить его:

   class Enums
   {
      public static bool IsSet( int flag, int bit ) { return (flag & bit) == bit; }
   }

но затем вы должны привести каждое значение к его базовому типу, как это:

   if( Enums.IsSet( (int)flag, (int)ReallyBigEnum.AnotherOption ) ) { ... }

, что также затрудняет кодирование и теряет преимущество проверки типов.

Эту же функцию можно написать для использования параметров объекта, но затем тип объекта и базовый базовый тип должны быть проверены.

Итак, я застрял со стандартным, избыточным способом наверху.

У кого-нибудь есть другие идеи относительно простого и простого способа проверки битовых полей Enum?

Большое спасибо.

Ответы [ 3 ]

6 голосов
/ 17 сентября 2010

До .Net 3.5 это ваш единственный вариант. В .Net 4.0 в перечислении есть метод HasFlag.

2 голосов
/ 17 сентября 2010
/// <summary>
/// Taken from https://stackoverflow.com/questions/9033/hidden-features-of-c/407325#407325
/// instead of doing (enum & value) == value you can now use enum.Has(value)
/// </summary>
/// <typeparam name="T">Type of enum</typeparam>
/// <param name="type">The enum value you want to test</param>
/// <param name="value">Flag Enum Value you're looking for</param>
/// <returns>True if the type has value bit set</returns>
public static bool Has<T>(this System.Enum type, T value)
{
   return (((int)(object)type & (int)(object)value) == (int)(object)value);
} 

Вот метод расширения, который я взял по ссылке выше

Использование:

MyFlagEnum e = MyFlagEnum.First | MyFlagEnum.Second;
if(e.Has(MyFlagEnum.First))
{
   // Do stuff
}
2 голосов
/ 17 сентября 2010
if((flag & ReallyBigEnum.AnotherOption) != 0) { ... }

ОБНОВЛЕНО:

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

Проверка того, чтоустанавливается любой из набора битов

. В этом случае просто используйте вариант версии с одним битом.

if((flag & (ReallyBigEnum.FirstOption | ReallyBigEnum.AnotherOption)) != 0) { ... }

Проверка того, что весь наборбиты установлены

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

const int ReallyBigEnum WickedAwesomeOptions = ReallyBigEnum.FirstOption | ReallyBigEnum.AnotherOption;
...
if (flag & WickedAwesomeOptions == WickedAwesomeOptions) { ... }

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

Если комбинация битов применяется широко, то вы можете добавить ее к самому перечислению.

[Flags]
enum ReallyBigEnum
{
    FirstOption = 1,
    AnotherOption = 2,
    WickedAwesomeOptions = FirstOption | AnotherOption,
}
....
if (flag & ReallyBigEnum.WickedAwesomeOptions == ReallyBigEnum.WickedAwesomeOptions) { ... }
...