2013-09-18 4 views
2

Может кто-нибудь, пожалуйста, помогите мне понять внутреннюю логику метода HasFlag для класса enum? Позвольте мне сначала объяснить мое требование. Я уже создал enum с атрибутом флага, а затем использовал функцию HasFlag(), чтобы получить выбранную комбинацию из значения битового флага. Но здесь мои требования разные. У меня есть таблица в моей БД, в которой перечислены разные значения перечисления. структура выглядит следующим образом.Что такое внутренняя логика для реализации функции Enum HasFlag

EnumTypeID EnumVal  EnumID  Description 
=========== ========== ========= ================ 
    1   enum1   0   xxxxxxxxx 
    1   enum2   1   xxxxxxxxx 
    1   enum3   2   xxxxxxxxx 
    2   enum4   0   xxxxxxxxx 
    2   enum5   1   xxxxxxxxx 

Скажем, у меня есть еще одна таблица, которая хранит комбинацию окончательного флага для EnumTypeID 1. Так что столбец таблицы предполагают, чтобы сохранить различные комбинации, как

0 = Nothing selected 
1 = enum1 selected 
2 = enum2 selected 
3 = enum1 & enum2 selected 
4 = enum3 selected 
5 = enum1 & enum3 selected 
6 = enum2 & enum3 selected 
7 = enum1 & enum2 & enum3 selected 

======= ================================================== ====

Теперь, как я могу программно (в C# .net4.5) достичь этого. Мне нужно сначала запросить первую таблицу и получить список перечислений для определенного EnumTypeID. Теперь мне нужно получить значение из второй таблицы для выбранного флага (скажем, значение равно 5). Тогда как я могу сказать, что в основном enum1 & enum3 выбран через код?

+1

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

+0

На самом деле я не хочу создавать Enum, но хочу использовать концепцию атрибута флага Enum. Мои перечисления будут поступать из DataBase. на основе значений этих enumIds мне нужно написать код, который будет динамически создавать 2 значения мощности. И тогда мне нужно сравнить это с значениями Flag из DB снова. –

ответ

2

, как вы можете увидеть в ниже связать HasFlag возвращает результат thisInstance и флаг = флаг выражения

Enum.HasFlag

см замечания раздел

и если я получил ваш вопрос правильно вас нужен такой запрос:

select * from SecondTable where FlagColumn & 5 = 5 
+0

Спасибо за ответ. Я получил помощь по ссылке, которую вы упомянули. –

1

Если бы мне пришлось выполнить t метод Enum.HasFlag, я бы написал это так.

public static bool HasFlag2(this Enum e, Enum flag) 
{ 
    // Check whether the flag was given 
    if (flag == null) 
    { 
     throw new ArgumentNullException("flag"); 
    } 

    // Compare the types of both enumerations 
    if (!e.GetType().IsEquivalentTo(flag.GetType())) 
    { 
     throw new ArgumentException(string.Format(
      "The type of the given flag is not of type {0}", e.GetType()), 
      "flag"); 
    } 

    // Get the type code of the enumeration 
    var typeCode = e.GetTypeCode(); 

    // If the underlying type of the flag is signed 
    if (typeCode == TypeCode.SByte || typeCode == TypeCode.Int16 || typeCode == TypeCode.Int32 || typeCode == TypeCode.Int64) 
    { 
     return (Convert.ToInt64(e) & Convert.ToInt64(flag)) != 0; 
    } 

    // If the underlying type of the flag is unsigned 
    if (typeCode == TypeCode.Byte || typeCode == TypeCode.UInt16 || typeCode == TypeCode.UInt32 || typeCode == TypeCode.UInt64) 
    { 
     return (Convert.ToUInt64(e) & Convert.ToUInt64(flag)) != 0; 
    } 

    // Unsupported flag type 
    throw new Exception(string.Format("The comparison of the type {0} is not implemented.", e.GetType().Name)); 
} 

Он выполняет двоичное сравнение с оператором AND. Больше информации here. При необходимости вы можете проверить его поведение в Visual Studio, это метод расширения.

Надеюсь, это поможет.

EDIT 2014-01-10

Тип Enum не реализует оператор &, что делает нашу работу труднее при попытке сравнить флаги вручную. Они должны быть введены в базовый тип перечисления (который реализует оператор &).

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

+0

'enum' не обязательно использовать' int' в качестве своего основного представления; ваш метод будет терпеть неудачу с любым, кто использует что-то другое. – supercat

+0

@supercat: Спасибо за ваш комментарий, вы правы. Я обновил свой пост, чтобы принять это во внимание. – ZenLulz

+0

Если я определяю перечисление '[Flags] enum MyEnum {A = 1, B = 2, C = 4, D = 8}' then '(MyEnum.B | MyEnum.C) .HasFlag (MyEnum.C | MyEnum. D) 'возвращает false, тогда как' (MyEnum.B | MyEnum.C) .HasFlag2 (MyEnum.C | MyEnum.D) 'возвращает true. Это потому, что HasFlag проверяет '(e & flag) == флаг', а не' (e & flag)! = 0'. Какая жалость, поскольку я хотел повести вашу версию :) –

Смежные вопросы