[ACCEPTED]-Generic extension method to see if an enum contains a flag-enums

Accepted answer
Score: 57

I based this method off of a bunch of SO 7 & Google searches, and a by using reflector 6 to see what MS did for the .NET 4 HasFlags 5 method.

public static class EnumExt
{
    /// <summary>
    /// Check to see if a flags enumeration has a specific flag set.
    /// </summary>
    /// <param name="variable">Flags enumeration to check</param>
    /// <param name="value">Flag to check for</param>
    /// <returns></returns>
    public static bool HasFlag(this Enum variable, Enum value)
    {
        if (variable == null)
            return false;

        if (value == null)
            throw new ArgumentNullException("value");

        // Not as good as the .NET 4 version of this function, but should be good enough
        if (!Enum.IsDefined(variable.GetType(), value))
        {
            throw new ArgumentException(string.Format(
                "Enumeration type mismatch.  The flag is of type '{0}', was expecting '{1}'.",
                value.GetType(), variable.GetType()));
        }

        ulong num = Convert.ToUInt64(value);
        return ((Convert.ToUInt64(variable) & num) == num);

    }

}

Notes:

  • This handles nulls
  • Does type checking
  • Converts to a ulong, and can handle any positive enum value. Microsoft cautions against the use of negative flags enumerations anyway:

    Use caution if you define a 4 negative number as a flag enumerated constant 3 because many flag positions might be set 2 to 1, which might make your code confusing 1 and encourage coding errors.

Score: 7

Not sure if you're using .NET 4.0 or not, but 2 it comes with the static method Enum.HasFlags().

-- Code 1 Removed (the accepted solution has it already) --

Score: 5

This is my approach this is Type safe and 22 doesn't do any boxing or unboxing. It throws 21 an exception if the type is not an enum. There 20 is a technique you can use if you want to 19 turn it into a public static method that 18 will be typed to Enum's, but it can't be 17 an extension method then. There is also 16 no need to check for null, as the struct 15 contraint blocks out nullable enum's as 14 well. I don't think there is much to be 13 done to improve this code, with the exception 12 of maybe writing it in F# or C++/CLI so 11 that you can put an enum constraint on it. The 10 idea is to build a function using expression 9 trees that will convert the enum to either 8 long if its anything but a ulong based enum, or 7 ulong and then and them, essentially producing:: return value & flag == flag

public static class EnumExtensions
 {
  #region Public Static Methods 
  /// <summary>
  /// Determines whether the specified value has flags. Note this method is up to 60 times faster
  /// than the one that comes with .NET 4 as it avoids any explict boxing or unboxing. 
  /// </summary>
  /// <typeparam name="TEnum">The type of the enum.</typeparam>
  /// <param name="value">The value.</param>
  /// <param name="flag">The flag.</param>
  /// <returns>
  ///  <c>true</c> if the specified value has flags; otherwise, <c>false</c>.
  /// </returns>
  /// <exception cref="ArgumentException">If TEnum is not an enum.</exception>
  public static bool HasFlags<TEnum>(this TEnum value, TEnum flag) where TEnum:struct,IComparable,IConvertible,IFormattable
  {
   return EnumExtensionsInternal<TEnum>.HasFlagsDelegate(value, flag);
  }
  #endregion Public Static Methods 

  #region Nested Classes 

  static class EnumExtensionsInternal<TEnum> where TEnum : struct,IComparable, IConvertible, IFormattable
  {
  #region Public Static Variables 
   /// <summary>
   /// The delegate which determines if a flag is set.
   /// </summary>
   public static readonly Func<TEnum, TEnum, bool> HasFlagsDelegate = CreateHasFlagDelegate();
  #endregion Public Static Variables 

  #region Private Static Methods 
   /// <summary>
   /// Creates the has flag delegate.
   /// </summary>
   /// <returns></returns>
   private static Func<TEnum, TEnum, bool> CreateHasFlagDelegate()
   {
    if(!typeof(TEnum).IsEnum)
    {
     throw new ArgumentException(string.Format("{0} is not an Enum", typeof(TEnum)), typeof(EnumExtensionsInternal<>).GetGenericArguments()[0].Name);
    }
    ParameterExpression valueExpression = Expression.Parameter(typeof(TEnum));
    ParameterExpression flagExpression = Expression.Parameter(typeof(TEnum));
    ParameterExpression flagValueVariable = Expression.Variable(Type.GetTypeCode(typeof(TEnum)) == TypeCode.UInt64 ? typeof(ulong) : typeof(long));
    Expression<Func<TEnum, TEnum, bool>> lambdaExpression = Expression.Lambda<Func<TEnum, TEnum, bool>>(
      Expression.Block(
        new[] { flagValueVariable },
        Expression.Assign(
          flagValueVariable,
          Expression.Convert(
            flagExpression,
            flagValueVariable.Type
          )
        ),
        Expression.Equal(
          Expression.And(
            Expression.Convert(
              valueExpression,
              flagValueVariable.Type
            ),
            flagValueVariable
          ),
          flagValueVariable
        )
      ),
      valueExpression,
      flagExpression
    );
    return lambdaExpression.Compile();
   }
  #endregion Private Static Methods 
  }
  #endregion Nested Classes 
 }

As 6 I forgot that the expression tree above 5 is .NET 4 only the following method should 4 work in .NET 3.5 to create the same expression 3 tree::

        private static Func<TEnum, TEnum, bool> CreateHasFlagDelegate2()
        {
            if(!typeof(TEnum).IsEnum)
            {
                throw new ArgumentException(string.Format("{0} is not an Enum", typeof(TEnum)), typeof(EnumExtensionsInternal<>).GetGenericArguments()[0].Name);
            }
            ParameterExpression valueExpression = Expression.Parameter(
                    typeof(TEnum),
                    typeof(TEnum).Name
            );
            ParameterExpression flagExpression = Expression.Parameter(
                    typeof(TEnum),
                    typeof(TEnum).Name
            );
            var targetType = Type.GetTypeCode(typeof(TEnum)) == TypeCode.UInt64 ? typeof(ulong) : typeof(long);
            Expression<Func<TEnum, TEnum, bool>> lambdaExpression = Expression.Lambda<Func<TEnum, TEnum, bool>>(
                            Expression.Equal(
                                    Expression.And(
                                            Expression.Convert(
                                                    valueExpression,
                                                    targetType
                                            ),
                                            Expression.Convert(
                                                flagExpression,
                                                targetType
                                            )
                                    ),
                                    Expression.Convert(
                                        flagExpression,
                                        targetType
                                    )
                            ),
                    valueExpression,
                    flagExpression
            );
            return lambdaExpression.Compile();
        }

this version should compile in .NET 2 3.5 and if it doesn't I can't understand 1 why.

Score: 3

Unfortunately no there is not a good way 7 to make an extension method like this. In 6 order for this to work you'd need to have 5 a generic method which operated on enum values. Unfortunately 4 there is no way to constrain generic arguments 3 to be an enum

// Ilegal
public static bool Contains<T>(this T value, T flag) where T : enum {
  ...
}

The best I've come up with 2 is the following

public static bool HasFlag<T>(this System.Enum e, T flag) 
{
    var intValue = (int)(object)e;
    var intFlag = (int)(object)flag;
    return (intValue & intFlag) != 0;
}

However it's limited in 1 several ways

  • Not type safe because there is no requirement the value and the flag have the same type
  • Assumes that all enum values are int based.
  • Causes boxing to occur for a simple bit check
  • Will throw if e is null
Score: 2

You can basically use your existing extension 5 method, byt use the Enum type instead of MyEnum. The 4 problem then is that it doesn't know the 3 enums are flags and won't allow the & operator, so 2 you just have to convert the enum values 1 to numbers.

    public static bool Contains(this Enum keys, Enum flag)
    {
        if (keys.GetType() != flag.GetType())
            throw new ArgumentException("Type Mismatch");
        return (Convert.ToUInt64(keys) & Convert.ToUInt64(flag)) != 0;
    }

And a unit test for good measure:

    [TestMethod]
    public void TestContains()
    {
        var e1 = MyEnum.One | MyEnum.Two;
        Assert.IsTrue( e1.Contains(MyEnum.Two) );

        var e2 = MyEnum.One | MyEnum.Four;
        Assert.IsFalse(e2.Contains(MyEnum.Two));
    }
Score: 2

I have another approach here that I just 13 cooked up quickly using the fact that Delegate.CreateDelegate 12 allows conversion between methods for Enum's 11 and their underlying types. The following 10 approach is much like my previous answer 9 but I feel might be easier to read for people 8 who don't know expression tree syntax. Basically 7 we know that Enums only have 8 possible 6 underlying types, and so we just create 5 a static method for each call it could use. Since 4 I'm going for brevity I use anonymous methods 3 which happened to be named the same thing 2 as the possible typecode values.This approach 1 will work in .Net 3.5::

public static class EnumHelper
{
    delegate bool HasFlag<T>(T left,T right);
    static readonly HasFlag<Byte> Byte = (x,y)=> (x&y) ==y;
    static readonly HasFlag<SByte> Sbyte = (x,y)=> (x&y) ==y;
    static readonly HasFlag<Int16> Int16 = (x,y)=> (x&y) ==y;
    static readonly HasFlag<UInt16> UInt16 = (x,y)=> (x&y) ==y;
    static readonly HasFlag<Int32> Int32 = (x,y)=> (x&y) ==y;
    static readonly HasFlag<UInt32> UInt32 = (x,y)=> (x&y) ==y;
    static readonly HasFlag<Int64> Int64 = (x,y)=> (x&y) ==y;
    static readonly HasFlag<UInt64> UInt64 = (x,y)=> (x&y) ==y;

    public static bool HasFlags<TEnum>(this TEnum @enum,TEnum flag) where TEnum:struct,IConvertible,IComparable,IFormattable
    {
        return Enum<TEnum>.HasFlag(@enum,flag);
    }
    class Enum<TEnum> where TEnum:struct,IConvertible,IComparable,IFormattable
    {
        public static HasFlag<TEnum> HasFlag = CreateDelegate();
        static HasFlag<TEnum> CreateDelegate()
        {
            if (!typeof(TEnum).IsEnum) throw new ArgumentException(string.Format("{0} is not an enum", typeof(TEnum)), typeof(Enum<>).GetGenericArguments()[0].Name);
            var delegateName = Type.GetTypeCode(typeof(TEnum)).ToString();
            var @delegate = typeof(EnumHelper).GetField(delegateName,BindingFlags.Static | BindingFlags.NonPublic).GetValue(null) as Delegate;
            return Delegate.CreateDelegate(typeof(HasFlag<TEnum>), @delegate.Method) as HasFlag<TEnum>;
        }
    }
}
Score: 2

Another way of implementing HasFlag function for 15 the .NET Framework 3.5.

public static bool HasFlag(this Enum e, Enum flag)
{
    // Check whether the flag was given
    if (flag == null)
    {
        throw new ArgumentNullException("flag");
    }

    // Compare the types of both enumerations
    if (e.GetType() != (flag.GetType()))
    {
        throw new ArgumentException(string.Format(
            "The type of the given flag is not of type {0}", e.GetType()),
            "flag");
    }

    // Get the type code of the enumeration
    var typeCode = e.GetTypeCode();

    // If the underlying type of the flag is signed
    if (typeCode == TypeCode.SByte || typeCode == TypeCode.Int16 || typeCode == TypeCode.Int32 ||
        typeCode == TypeCode.Int64)
    {
        return (Convert.ToInt64(e) & Convert.ToInt64(flag)) != 0;
    }

    // If the underlying type of the flag is unsigned
    if (typeCode == TypeCode.Byte || typeCode == TypeCode.UInt16 || typeCode == TypeCode.UInt32 ||
        typeCode == TypeCode.UInt64)
    {
        return (Convert.ToUInt64(e) & Convert.ToUInt64(flag)) != 0;
    }

    // Unsupported flag type
    throw new Exception(string.Format("The comparison of the type {0} is not implemented.", e.GetType().Name));
}

This extension method 14 supports all the possible types for an enumeration 13 (byte, sbyte, short, ushort, int, uint, long and ulong). Basically, the method 12 checks if the given enumeration is signed/unsigned 11 and converts the flag to the type with the 10 highest size of the supported types for 9 an enumeration. Then, a simple comparison 8 is performed using the & operator.

As explained 7 in other posts, we cannot define a constraint 6 of the generic type with an enumeration 5 and it doesn't make sense to use generic 4 with a struct constraint, because w developers 3 could insert other enumerations types or 2 structures then. So, I think it's better 1 to not use generic method for that.

Score: 1

Here is a very performant, non-boxing, allocation-free, safe 7 (i.e. free from the unsafe keyword), branchless solution.

It 6 works by reinterpreting the enum value as 5 a ulong, regardless of its type or size. It achieves 4 this by writing ulong value 0 onto the stack, reinterpreting 3 those bytes as a sequence of one or more 2 TEnums, writing the TEnum value into location [0], and 1 then reading back the ulong value.

public static class EnumHelper
{
    static EnumHelper()
    {
        // Required to get correct behavior in GetNumericValue, where we overlap the enum type with a ulong, left-aligned
        if (!BitConverter.IsLittleEndian)
            throw new NotSupportedException("This type is only supported on little-endian architectures.");
    }
        
    public static bool HasFlag<T>(T subject, T flag)
        where T : unmanaged, Enum
    {
        var numericSubject = GetNumericValue(subject);
        var numericFlag = GetNumericValue(flag);

        return (numericSubject & numericFlag) == numericFlag;
    }

    /// <summary>
    /// <para>
    /// Returns the numeric value of the given <paramref name="enumValue"/>.
    /// </para>
    /// <para>
    /// The resulting <see cref="ulong"/> can be cast to the intended integral type, even if it is a signed type.
    /// </para>
    /// </summary>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public static ulong GetNumericValue<T>(T enumValue)
        where T : unmanaged, Enum
    {
        Span<ulong> ulongSpan = stackalloc ulong[] { 0UL };
        Span<T> span = MemoryMarshal.Cast<ulong, T>(ulongSpan);

        span[0] = enumValue;

        return ulongSpan[0];
    }
}
Score: 0

This is an example of something that should 1 work.

public static bool IsValid<T>(this T value)
{
    return Enum.IsDefined(value.GetType(), value);
}

More Related questions