Ответ 1
До .Net 3.5 это ваш единственный вариант. В .Net 4.0 существует метод HasFlag
для перечисления.
При использовании 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?
Большое спасибо.
До .Net 3.5 это ваш единственный вариант. В .Net 4.0 существует метод HasFlag
для перечисления.
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) { ... }
/// <summary>
/// Taken from /info/638/hidden-features-of-c/10131#10131
/// 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
}