Метод расширения перечисления битового поля для возврата словаря включенных значений

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

Дано:

[Flags]
public enum PlanetsEnum
{
  Mercury=1,
  Venus=2,
  Earth=4,
  Mars=8,
  Jupiter=16,
  //etc....
}

Я хотел бы создать метод расширения, который возвращает словарь только выбранных значений. Так что если:

PlanetsEnum neighbors = PlanetsEnum.Mars | PlanetEnum.Venus; //10

IDictionary dict = neighbors.ToDictionary();

foreach (KeyValuePair<String, Int32> kvp in dict)
{
  Console.WriteLine(kvp.Key);
}

/*
*  Should Print:
*      Mars
*      Venus
*/

Я ожидаю, что Марс и Венера будут записаны в консоль, но вместо этого я вижу все значения PlanetEnum. Вот мой код метода расширения:

public static IDictionary<string, Int32> ToDictionary(this Enum enumeration)
{
  Type type = enumeration.GetType();
  return Enum.GetValues(type).Cast&lt;Int32>().ToDictionary(field => Enum.GetName(type, field));
}

Кто-нибудь видит, что я делаю неправильно? Я знаю, что Enum.GetValues возвращает все поля типа перечисления, как мне заставить его возвращать только поля экземпляра перечисления?

Большое спасибо за любую помощь,

Кейт


person Community    schedule 03.02.2010    source источник


Ответы (2)


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

public static IDictionary<string, int> ToDictionary(this Enum enumeration)
{
    int value = (int)(object)enumeration;
    return Enum.GetValues(enumeration.GetType()).OfType<int>().Where(v => (v & value) == value).ToDictionary(v => Enum.GetName(enumeration.GetType(), v));
}

Изменить. Небольшое объяснение того, почему мы используем (int)(object)enumeration состав:

Побитовые операторы работают только с целочисленными типами (такими как int) и логическими типами, но Enum нельзя напрямую преобразовать в int. Таким образом, мы должны привести к объекту и предполагать, что он на самом деле представляет тип int в качестве базового типа — компилятор позволит нам привести объект к типу int. Если перечисление не основано на целых числах, это вызовет исключение времени выполнения.

person Rex M    schedule 03.02.2010
comment
очень хорошо! Почему вы сначала привели перечисление к объекту? - person Keith; 04.02.2010
comment
@unknown, потому что побитовые операторы работают только с целочисленными типами (например, int) и логическими типами, но Enum нельзя напрямую преобразовать в int. Таким образом, мы должны привести к объекту и предполагать, что он на самом деле представляет int в качестве базового типа — компилятор позволит нам привести объект к типу int. Если перечисление не основано на целых числах, это вызовет исключение времени выполнения. - person Rex M; 04.02.2010

Попробуйте следующее. Это работает только для Enum, которые являются int32.

public static IDictionary<String, Int32> ToDictionary(this Enum enumeration)
{
    var map = new Dictionary<string, int>();
    var value = (int)(object)enumeration;
    var type = enumeration.GetType();
    foreach (int cur in Enum.GetValues(type))
    {
        if (0 != (cur & value))
        {
            map.Add(Enum.GetName(type, cur),cur);
        }
    }
    return map;
}
person JaredPar    schedule 03.02.2010