使用Enum方法将通用方法约束到T

时间:2011-02-09 15:43:25

标签: c#-4.0 enums extension-methods

我一直在尝试为标记的枚举值编写实用程序扩展方法。此方法的目的是检索当前启用的所有标志的列表。

我想做的是:

 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 个答案:

答案 0 :(得分:2)

您可以做的最好的事情是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类中定义,并且不能继承其他类。

答案 1 :(得分:0)

我使用反射。只需在运行时自行调用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;
        }
    }
}