Ограничение универсального метода с использованием методов Enum для T - PullRequest
1 голос
/ 09 февраля 2011

Я пытался написать метод расширения утилиты для отмеченных значений перечисления. Цель этого метода - получить список всех флагов, которые в данный момент включены.

Что я хотел сделать, это:

 public static IEnumerable<T> GetFlags<T>(this T value) where T:Enum 
  {
     return Enum.GetValues(typeof(T)).OfType<Enum>().Where(value.HasFlag).Cast<T>(); 
  }

Однако, поскольку дженерики не работают с типом Enum, мне пришлось прибегнуть к следующему:

public static IEnumerable<T> GetFlags<T>(this Enum value) 
  {
     return Enum.GetValues(typeof(T)).OfType<Enum>().Where(value.HasFlag).Cast<T>(); 
  }

Есть ли способ обойти это, или я должен смириться с явной необходимостью объявлять тип при каждом вызове метода?

Ответы [ 2 ]

2 голосов
/ 09 февраля 2011

Лучшее, что вы можете сделать, это where T : struct.

Для методов без расширения вы можете использовать уродливый трюк:

public abstract class Enums<Temp> where Temp : class {
    public static TEnum Parse<TEnum>(string name) where TEnum : struct, Temp {
        return (TEnum)Enum.Parse(typeof(TEnum), name); 
    }
}
public abstract class Enums : Enums<Enum> { }

Enums.Parse<DateTimeKind>("Local")

Если хотите, вы можете дать Enums<Temp> закрытый конструктор и открытый вложенный абстрактный унаследованный класс с Temp как Enum, чтобы предотвратить унаследованные версии для не перечислений.

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

0 голосов
/ 25 июля 2012

Я использую отражение.Просто вызовите HasFlag (или любой другой метод, который вам нужен) самостоятельно во время выполнения.

Предложение where дает как можно больше ограничений.Затем, если ваш тип не является enum, этот код повысит TargetInvocationException.

/// <summary>
/// Gets the flags for the given enum value.
/// </summary>
/// <typeparam name="T">The enum type</typeparam>
/// <param name="enumValue">The enum value.</param>
/// <returns>The flagged values.</returns>
public static IEnumerable<T> GetFlags<T>(this T enumValue)
    where T : struct
{
    Type enumType = enumValue.GetType();
    foreach (T value in Enum.GetValues(enumType))
    {
        bool hasFlag = (bool)enumType.InvokeMember("HasFlag", BindingFlags.InvokeMethod, null, enumValue, new object[] { value });
        if (hasFlag)
        {
            yield return value;
        }
    }
}
...