列出标志枚举中的所有位名称

我正在尝试创建一个帮助方法来列出Enum值中设置的所有位的名称(用于记录目的)。 我想要一个方法,它将返回一些变量中设置的所有枚举值的列表。 在我的例子中

[Flag] Enum HWResponse { None = 0x0, Ready = 0x1, Working = 0x2, Error = 0x80, } 

我把它提供给0x81,它应该为我提供一个包含{Ready, Error}IEnumerable

由于我没有找到更简单的方法,我尝试编写下面的代码,但我无法编译。

 public static IEnumerable MaskToList(Enum mask) { if (typeof(T).IsSubclassOf(typeof(Enum)) == false) throw new ArgumentException(); List toreturn = new List(100); foreach(T curValueBit in Enum.GetValues(typeof (T)).Cast()) { Enum bit = ((Enum) curValueBit); // Here is the error if (mask.HasFlag(bit)) toreturn.Add(curValueBit); } return toreturn; } 

在这个版本的代码中,编译器抱怨它无法将T转换为Enum。

我做错了什么? 有更好(更简单)的方法吗? 我怎么能演员?

另外,我试着把方法写成

 public static IEnumerable MaskToList(Enum mask) where T:Enum 

但Enum属于一种特殊类型,禁止’where’语法(使用C#4.0)

这是使用LINQ编写它的简单方法:

 public static IEnumerable MaskToList(Enum mask) { if (typeof(T).IsSubclassOf(typeof(Enum)) == false) throw new ArgumentException(); return Enum.GetValues(typeof(T)) .Cast() .Where(m => mask.HasFlag(m)) .Cast(); } 

如果您想要的最终结果是名称的字符串列表,只需调用mask.ToString()

如果枚举是这样定义的,你会怎么做:

 [Flags] enum State { Ready = 1, Waiting = 2, ReadyAndWaiting = 3 } 

至于解决编译器错误,这应该这样做:

 Enum bit = (Enum)(object)curValueBit; 

Jon Skeet有一个叫做无约束旋律的项目,允许你在编译后通过重写IL来添加枚举约束。 这是有效的,因为CLR支持这样的约束,即使C#没有。

另一个想法:将GetValues的返回值直接转换为T[]会更有效:

 foreach(T curValueBit in (T[])Enum.GetValues(typeof (T))) 

在Gabe的回答基础上,我想出了这个:

 public static class EnumHelper where T : struct { // ReSharper disable StaticFieldInGenericType private static readonly Enum[] Values; // ReSharper restore StaticFieldInGenericType private static readonly T DefaultValue; static EnumHelper() { var type = typeof(T); if (type.IsSubclassOf(typeof(Enum)) == false) { throw new ArgumentException(); } Values = Enum.GetValues(type).Cast().ToArray(); DefaultValue = default(T); } public static T[] MaskToList(Enum mask, bool ignoreDefault = true) { var q = Values.Where(mask.HasFlag); if (ignoreDefault) { q = q.Where(v => !v.Equals(DefaultValue)); } return q.Cast().ToArray(); } } 

我组织的东西有点不同,即我把类型检查(即:validationT实际上是一个枚举)和在静态构造函数中获取枚举值,这样只执行一次(这将是性能改进 ) 。

另外,我添加了一个可选参数,因此您可以忽略枚举的典型“零”/“无”/“不适用”/“未定义”/ etc值。

如果只做这样的事情怎么办:

 public static IEnumerable MaskToList(Enum mask) { if (typeof(T).IsSubclassOf(typeof(Enum)) == false) throw new ArgumentException(); List toreturn = new List(100); foreach(T curValueBit in Enum.GetValues(typeof (T)).Cast()) { Enum bit = (curValueBit as Enum); // The only difference is actually here, // use "as", instead of (Enum) cast if (mask.HasFlag(bit)) toreturn.Add(curValueBit); } return toreturn; } 

由于没有编译时间检查。 编译器只是“相信”你,希望你知道你在做什么,所以编译时错误没有提出