Comparing enum flags in C#

后端 未结 7 2279
一个人的身影
一个人的身影 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:28

    I have used this to compare flags

    public static bool IsSet<T>(this T input, T match)
    {
        return (Convert.ToUInt32(input) & Convert.ToUInt32(match)) != 0;
    }
    

    Here you can do the different conversions. From int to short to long.

    0 讨论(0)
  • 2021-02-07 19:31

    or... public static bool IsSet(this Enum value, Enum compare) { int baseValue = value.ToInt32(); int compareValue = compare.ToInt32(); if (baseValue == 0) return false; return ((baseValue & compareValue) == compareValue); }

    0 讨论(0)
  • 2021-02-07 19:32

    This should do the job for enum types with any underlying types:

    public static bool IsSet<T>(this T value, T flags) where T : struct
    {
        return (Convert.ToInt64(value) & Convert.ToInt64(flags)) ==
            Convert.ToInt64(flags);
    }
    

    Convert.ToInt64 is used because a 64-bit integer is the "widest" integral type possible, to which all enum values can be cast (even ulong). Note that char is not a valid underlying type. It seems that it is not valid in C#, but it is in general valid in CIL/for the CLR.

    Also, you can't enforce a generic type constraint for enums (i.e. where T : struct); the best you can do is use where T : struct to enforce T to be a value type, and then optionally perform a dynamic check to ensure that T is an enum type.

    For completeness, here is my very brief test harness:

    static class Program
    {
        static void Main(string[] args)
        {
            Debug.Assert(Foo.abc.IsSet(Foo.abc));
            Debug.Assert(Bar.def.IsSet(Bar.def));
            Debug.Assert(Baz.ghi.IsSet(Baz.ghi));
        }
    
        enum Foo : int
        {
            abc = 1,
            def = 10,
            ghi = 100
        }
    
        enum Bar : sbyte
        {
            abc = 1,
            def = 10,
            ghi = 100
        }
    
        enum Baz : ulong
        {
            abc = 1,
            def = 10,
            ghi = 100
        }
    }
    
    0 讨论(0)
  • 2021-02-07 19:34

    Personally, I think that look fine because you've wrapped it into a single purpose function. If you had that code scattered through an entire program I think you would have some problems, but what you've created improves clarity everywhere it is used and the function itself is clear enough what it does.

    Just my opinion of course.

    You could though, use the is keyword, which might help a little

    public static bool IsSet<T>(this T value, T flags) where T : Enum
    { 
        if (value is int)
        {
            return ((int)(object)a & (int)(object)b) == (int)(object)b);
        }
        //etc...
    
    0 讨论(0)
  • 2021-02-07 19:35

    Simply use the Enum.HasFlag() Method !

    0 讨论(0)
  • 2021-02-07 19:36

    For me it looks overcomplicated. How about this (keeping in mind that enum is always mapped to an integer value type):

    public static bool IsSet<T>(T value, T flags) where T : struct
    {
        // You can add enum type checking to be perfectly sure that T is enum, this have some cost however
        // if (!typeof(T).IsEnum)
        //     throw new ArgumentException();
        long longFlags = Convert.ToInt64(flags);
        return (Convert.ToInt64(value) & longFlags) == longFlags;
    }
    
    0 讨论(0)
提交回复
热议问题