Метод расширения перечисления битового поля для возврата словаря включенных значений - PullRequest
2 голосов
/ 04 февраля 2010

Перечисления могут быть непонятными. Я пытаюсь создать метод расширения для типа 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 возвращает все поля типа enum, как мне получить его, чтобы он возвращал только поля экземпляра enum?

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

Keith

Ответы [ 3 ]

3 голосов
/ 04 февраля 2010

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

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.Если перечисление не основано на целых числах, это вызовет исключение времени выполнения.

2 голосов
/ 04 февраля 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;
}
1 голос
/ 07 июля 2011
public enum CustomerType
{
    Standard = 0,
    Trade = 1
}

ddCustomerTypes.DataSource = (new Domain.CustomerType()).ToDictionary();
ddCustomerTypes.DataBind();

public static class EnumExtensionMethods
{
    public static Dictionary<string, object> ToDictionary(this Enum enumeration)
    {
        Array names = Enum.GetNames(enumeration.GetType());

        Dictionary<string, object> dictionary = new Dictionary<string, object>();

        foreach (string name in names)
        {
            dictionary.Add(name, typeof(Domain.CustomerType).GetField(name).GetRawConstantValue() );
        }

        return dictionary;
    }

    public static List<KeyValuePair<string, object>> ToList(this Enum enumObject)
    {
        return enumObject.ToDictionary().ToList();
    }
}
...