How to check if any flags of a flag combination are set?

前端 未结 16 630
佛祖请我去吃肉
佛祖请我去吃肉 2020-11-29 17:24

Let\'s say I have this enum:

[Flags]
enum Letters
{
     A = 1,
     B = 2,
     C = 4,
     AB = A | B,
     All = A | B | C,
}

To check i

相关标签:
16条回答
  • 2020-11-29 17:35

    To check if for example AB is set I can do this:

    if((letter & Letters.AB) == Letters.AB)

    Is there a simpler way to check if any of the flags of a combined flag constant are set than the following?

    This checks that both A and B are set, and ignores whether any other flags are set.

    if((letter & Letters.A) == Letters.A || (letter & Letters.B) == Letters.B)
    

    This checks that either A or B is set, and ignores whether any other flags are set or not.

    This can be simplified to:

    if(letter & Letters.AB)
    

    Here's the C for binary operations; it should be straightforward to apply this to C#:

    enum {
         A = 1,
         B = 2,
         C = 4,
         AB = A | B,
         All = AB | C,
    };
    
    int flags = A|C;
    
    bool anything_and_a = flags & A;
    
    bool only_a = (flags == A);
    
    bool a_and_or_c_and_anything_else = flags & (A|C);
    
    bool both_ac_and_anything_else = (flags & (A|C)) == (A|C);
    
    bool only_a_and_c = (flags == (A|C));
    

    Incidentally, the naming of the variable in the question's example is the singular 'letter', which might imply that it represents only a single letter; the example code makes it clear that its a set of possible letters and that multiple values are allowed, so consider renaming the variable 'letters'.

    0 讨论(0)
  • 2020-11-29 17:38

    I use extension methods to write things like that :

    if (letter.IsFlagSet(Letter.AB))
        ...
    

    Here's the code :

    public static class EnumExtensions
    {
        private static void CheckIsEnum<T>(bool withFlags)
        {
            if (!typeof(T).IsEnum)
                throw new ArgumentException(string.Format("Type '{0}' is not an enum", typeof(T).FullName));
            if (withFlags && !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
        {
            CheckIsEnum<T>(true);
            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
        {
            CheckIsEnum<T>(true);
            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
        {
            CheckIsEnum<T>(true);
            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
        {
            CheckIsEnum<T>(true);
            long lValue = 0;
            foreach (T flag in flags)
            {
                long lFlag = Convert.ToInt64(flag);
                lValue |= lFlag;
            }
            return (T)Enum.ToObject(typeof(T), lValue);
        }
    
        public static string GetDescription<T>(this T value) where T : struct
        {
            CheckIsEnum<T>(false);
            string name = Enum.GetName(typeof(T), value);
            if (name != null)
            {
                FieldInfo field = typeof(T).GetField(name);
                if (field != null)
                {
                    DescriptionAttribute attr = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
                    if (attr != null)
                    {
                        return attr.Description;
                    }
                }
            }
            return null;
        }
    }
    
    0 讨论(0)
  • 2020-11-29 17:38

    If you can use .NET 4 or higher than use HasFlag() method

    examples

    letter.HasFlag(Letters.A | Letters.B) // both A and B must be set
    

    same as

    letter.HasFlag(Letters.AB)
    
    0 讨论(0)
  • 2020-11-29 17:45

    If it really annoys you, you can write a function like that:

    public bool IsSet(Letters value, Letters flag)
    {
        return (value & flag) == flag;
    }
    
    if (IsSet(letter, Letters.A))
    {
       // ...
    }
    
    // If you want to check if BOTH Letters.A and Letters.B are set:
    if (IsSet(letter, Letters.A & Letters.B))
    {
       // ...
    }
    
    // If you want an OR, I'm afraid you will have to be more verbose:
    if (IsSet(letter, Letters.A) || IsSet(letter, Letters.B))
    {
       // ...
    }
    
    0 讨论(0)
  • 2020-11-29 17:47

    How about

    if ((letter & Letters.AB) > 0)
    

    ?

    0 讨论(0)
  • 2020-11-29 17:48

    You can use this extension method on enum, for any type of enums:

    public static bool IsSingle(this Enum value)
    {
        var items = Enum.GetValues(value.GetType());
        var counter = 0;
        foreach (var item in items)
        {
            if (value.HasFlag((Enum)item))
            {
                counter++;
            }
            if (counter > 1)
            {
                return false;
            }
        }
        return true;
    }
    
    0 讨论(0)
提交回复
热议问题