Anyone know a good workaround for the lack of an enum generic constraint?
Solution 1:
EDIT: This is now live in version 0.0.0.2 of UnconstrainedMelody.
(As requested on my blog post about enum constraints. I've included the basic facts below for the sake of a standalone answer.)
The best solution is to wait for me to include it in UnconstrainedMelody1. This is a library which takes C# code with "fake" constraints such as
where T : struct, IEnumConstraint
and turns it into
where T : struct, System.Enum
via a postbuild step.
It shouldn't be too hard to write IsSet
... although catering for both Int64
-based and UInt64
-based flags could be the tricky part. (I smell some helper methods coming on, basically allowing me to treat any flags enum as if it had a base type of UInt64
.)
What would you want the behaviour to be if you called
tester.IsSet(MyFlags.A | MyFlags.C)
? Should it check that all the specified flags are set? That would be my expectation.
I'll try to do this on the way home tonight... I'm hoping to have a quick blitz on useful enum methods to get the library up to a usable standard quickly, then relax a bit.
EDIT: I'm not sure about IsSet
as a name, by the way. Options:
- Includes
- Contains
- HasFlag (or HasFlags)
- IsSet (it's certainly an option)
Thoughts welcome. I'm sure it'll be a while before anything's set in stone anyway...
1 or submit it as a patch, of course...
Solution 2:
As of C# 7.3, there is now a built-in way to add enum constraints:
public class UsingEnum<T> where T : System.Enum { }
source: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/where-generic-type-constraint
Solution 3:
Darren, that would work if the types were specific enumerations - for general enumerations to work you have to cast them to ints (or more likely uint) to do the boolean math:
public static bool IsSet( this Enum input, Enum matchTo )
{
return ( Convert.ToUInt32( input ) & Convert.ToUInt32( matchTo ) ) != 0;
}
Solution 4:
Actually, it is possible, with an ugly trick. However, it cannot be used for extension methods.
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.IsSet<DateTimeKind>("Local")
If you want to, you can give Enums<Temp>
a private constructor and a public nested abstract inherited class with Temp
as Enum
, to prevent inherited versions for non-enums.