I'm trying to make a helper method for listing the names of all bits set in an Enum value (for logging purposes). I want have a method that would return the list of all the Enum values set in some variables. In my example
[Flag]
Enum HWResponse
{
None = 0x0,
Ready = 0x1,
Working = 0x2,
Error = 0x80,
}
I feed it 0x81, and it should provide me with a IEnumerable<HWResponse>
containing {Ready, Error}
.
As I didn't find a simpler way, I tried to write the code below, but I can't make it compile.
public static IEnumerable<T> MaskToList<T>(Enum mask)
{
if (typeof(T).IsSubclassOf(typeof(Enum)) == false)
throw new ArgumentException();
List<T> toreturn = new List<T>(100);
foreach(T curValueBit in Enum.GetValues(typeof (T)).Cast<T>())
{
Enum bit = ((Enum) curValueBit); // Here is the error
if (mask.HasFlag(bit))
toreturn.Add(curValueBit);
}
return toreturn;
}
On this version of the code, the compiler complains that it can't cast T to Enum.
What did I do wrong? Is there a better (simpler) way to do this? How could I make the cast?
Also, I tried to write the method as
public static IEnumerable<T> MaskToList<T>(Enum mask) where T:Enum
but Enum is of a special type that forbids the 'where' syntax (Using C# 4.0)
Building on Gabe's answer I came up with this :
I organized things a bit differently, namely I put the type check (i.e.: the verification that T is really an enumeration) and the obtaining of the enum values in the static constructor so this is done only once (this would be a performance improvement).
Another thing, I added an optional parameter so you can ignore the typical "zero" / "None" / "NotApplicable" / "Undefined" / etc value of the enumeration.
What if just do something like this:
As the
as
has not compile time check. Compiler here just "believes" you, hoping that you know what you're doing, so the compile time error not raised.Here's a simple way to write it using LINQ:
If your desired end result is a string list of names, just call
mask.ToString()
.What would you do if the enum were defined like this:
As to resolving the compiler error, this should do it:
Jon Skeet has a project called unconstrained melody that allows you to add the enum constraint, after compilation, by rewriting the IL. This works because the CLR supports such a constraint, even though C# does not.
Another thought: It will be more efficient to cast the return value of GetValues directly to
T[]
: