Comparing enum flags in C#

后端 未结 7 2270
一个人的身影
一个人的身影 2021-02-07 18:42

I need to detect if a flag is set within an enum value, which type is marked with the Flag attribute.

Usually it is made like that:

(value & flag) ==         


        
相关标签:
7条回答
  • 2021-02-07 19:37

    I wrote a set of extension methods for enums, in case you need it :

    public static class EnumExtensions
    {
        private static void CheckEnumWithFlags<T>()
        {
            if (!typeof(T).IsEnum)
                throw new ArgumentException(string.Format("Type '{0}' is not an enum", typeof(T).FullName));
            if (!Attribute.IsDefined(typeof(T), typeof(FlagsAttribute)))
                throw new ArgumentException(string.Format("Type '{0}' doesn't have the 'Flags' attribute", typeof(T).FullName));
        }
    
        public static bool IsFlagSet<T>(this T value, T flag) where T : struct
        {
            CheckEnumWithFlags<T>();
            long lValue = Convert.ToInt64(value);
            long lFlag = Convert.ToInt64(flag);
            return (lValue & lFlag) != 0;
        }
    
        public static IEnumerable<T> GetFlags<T>(this T value) where T : struct
        {
            CheckEnumWithFlags<T>();
            foreach (T flag in Enum.GetValues(typeof(T)).Cast<T>())
            {
                if (value.IsFlagSet(flag))
                    yield return flag;
            }
        }
    
        public static T SetFlags<T>(this T value, T flags, bool on) where T : struct
        {
            CheckEnumWithFlags<T>();
            long lValue = Convert.ToInt64(value);
            long lFlag = Convert.ToInt64(flags);
            if (on)
            {
                lValue |= lFlag;
            }
            else
            {
                lValue &= (~lFlag);
            }
            return (T)Enum.ToObject(typeof(T), lValue);
        }
    
        public static T SetFlags<T>(this T value, T flags) where T : struct
        {
            return value.SetFlags(flags, true);
        }
    
        public static T ClearFlags<T>(this T value, T flags) where T : struct
        {
            return value.SetFlags(flags, false);
        }
    
        public static T CombineFlags<T>(this IEnumerable<T> flags) where T : struct
        {
            CheckEnumWithFlags<T>();
            long lValue = 0;
            foreach (T flag in flags)
            {
                long lFlag = Convert.ToInt64(flag);
                lValue |= lFlag;
            }
            return (T)Enum.ToObject(typeof(T), lValue);
        }
    }
    

    The main drawback is that you can't specify where T : Enum : it is explicitly forbidden ("Constraint cannot be special class 'System.Enum'"), so the extension methods will appear in intellisense for all structs... I added the CheckEnumWithFlags method to check that the type is actually an enum, and has the Flags attribute.


    UPDATE : Jon Skeet recently started an interesting library called UnconstrainedMelody which does exactly the same sort of things, and works around the generic type constraint limitation mentioned above

    0 讨论(0)
提交回复
热议问题