C# 4.0 使用枚举方法将泛型方法约束为

C# 4.0 使用枚举方法将泛型方法约束为,c#-4.0,enums,extension-methods,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>(); } 公共静态IEnu

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

我想做的是:

 public static IEnumerable<T> GetFlags<T>(this T value) where T:Enum 
  {
     return Enum.GetValues(typeof(T)).OfType<Enum>().Where(value.HasFlag).Cast<T>(); 
  }
公共静态IEnumerable GetFlags(此T值),其中T:Enum
{
返回类型()的Enum.GetValues(typeof(T))。其中(value.HasFlag.Cast();
}
但是,由于泛型不适用于枚举类型,我不得不采取以下措施:

public static IEnumerable<T> GetFlags<T>(this Enum value) 
  {
     return Enum.GetValues(typeof(T)).OfType<Enum>().Where(value.HasFlag).Cast<T>(); 
  }
公共静态IEnumerable GetFlags(此枚举值)
{
返回类型()的Enum.GetValues(typeof(T))。其中(value.HasFlag.Cast();
}

有没有办法绕过这个问题,或者我应该在每次调用方法时显式地声明类型?

最好的方法是
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")
公共抽象类枚举,其中Temp:class{
公共静态TEnum解析(字符串名称),其中TEnum:struct,Temp{
return(TEnum)Enum.Parse(typeof(TEnum),name);
}
}
公共抽象类枚举:枚举{}
解析(“本地”)
如果愿意,可以将
Temp
设置为
Enum
,为
Enum
提供一个私有构造函数和一个公共嵌套的抽象继承类,以防止非Enum的继承版本


您不能使用此技巧生成扩展方法,因为扩展方法必须在
静态类中定义,并且不能继承其他类。

我使用反射。您只需在运行时自己调用
HasFlag
(或任何您需要的方法)

where
子句提供了尽可能多的约束。然后,如果您的类型不是
enum
,则此代码将引发
targetingException

/// <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;
        }
    }
}
//
///获取给定枚举值的标志。
/// 
///枚举类型
///枚举值。
///标记的值。
公共静态IEnumerable GetFlags(此枚举值)
其中T:struct
{
类型enumType=enumValue.GetType();
foreach(枚举中的T值。GetValues(枚举类型))
{
bool hasFlag=(bool)enumType.InvokeMember(“hasFlag”,BindingFlags.InvokeMethod,null,enumValue,新对象[]{value});
如果(hasFlag)
{
收益回报值;
}
}
}

它的可能复制品没有其他替代品那么难看。实际上,相当巧妙。