C#, Flags Enum, Generic function to look for a flag

后端 未结 11 1520
陌清茗
陌清茗 2020-12-30 05:43

I\'d like one general purpose function that could be used with any Flags style enum to see if a flag exists.

This doesn\'t compile, but if anyone has a suggestion, I

相关标签:
11条回答
  • 2020-12-30 05:59

    Why not write an extension method for this? I did this in another post

    public static class EnumerationExtensions {
    
        public static bool Has<T>(this System.Enum type, T value) {
            try {
                return (((int)(object)type & (int)(object)value) == (int)(object)value);
            } 
            catch {
                return false;
            }
        }
        //... etc...
    
    }
    
    //Then use it like this
    bool hasValue = permissions.Has(PermissionTypes.Delete);
    

    It could use a little refinement (since it assumes everything can be cast as an int), but it could get you started...

    0 讨论(0)
  • 2020-12-30 06:00

    No, you can't do this with C# generics. However, you could do:

    public static bool IsEnumFlagPresent<T>(T value, T lookingForFlag) 
        where T : struct
    {
        int intValue = (int) (object) value;
        int intLookingForFlag = (int) (object) lookingForFlag;
        return ((intValue & intLookingForFlag) == intLookingForFlag);
    }
    

    This will only work for enums which have an underlying type of int, and it's somewhat inefficient because it boxes the value... but it should work.

    You may want to add an execution type check that T is actually an enum type (e.g. typeof(T).BaseType == typeof(Enum))

    Here's a complete program demonstrating it working:

    using System;
    
    [Flags]
    enum Foo
    {
        A = 1,
        B = 2,
        C = 4,
        D = 8
    }
    
    class Test
    {
        public static Boolean IsEnumFlagPresent<T>(T value, T lookingForFlag) 
            where T : struct
        {
            int intValue = (int) (object) value;
            int intLookingForFlag = (int) (object) lookingForFlag;
            return ((intValue & intLookingForFlag) == intLookingForFlag);
        }
    
        static void Main()
        {
            Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.A));
            Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.B));
            Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.C));
            Console.WriteLine(IsEnumFlagPresent(Foo.B | Foo.C, Foo.D));
        }
    }
    
    0 讨论(0)
  • 2020-12-30 06:00

    For what its worth, I recently read that this feature will be part of .NET 4.0. Specifically, it is implemented in the Enum.HasFlag() function.

    0 讨论(0)
  • 2020-12-30 06:03

    You can do this without generics:

    static bool ContainsFlags(Enum value, Enum flag)
    {
        if (Enum.GetUnderlyingType(value.GetType()) == typeof(ulong))
            return (Convert.ToUInt64(value) & Convert.ToUInt64(flag)) == Convert.ToUInt64(flag);
        else
            return (Convert.ToInt64(value) & Convert.ToInt64(flag)) == Convert.ToInt64(flag);
    }
    

    I'm converting to Int64 in this case, which should handle every case except ulong, which is why the extra check...

    0 讨论(0)
  • 2020-12-30 06:09

    You're looking to replace one line of code with a function that wraps one line of code? I'd say to just use the one line of code...

    0 讨论(0)
  • 2020-12-30 06:11

    Worth pointing out that simply providing some static overloads for all the integral types will work so long as you know you are working with a specific enum. They won't work if the consuming code is likewise operating on where t : struct

    If you need to deal with arbitrary (struct) T

    You cannot currently do a fast conversion of a generically typed struct into some alternate bitwise form (i.e. roughly speaking a reinterpret_cast) without using C++/CLI

    generic <typename T>
    where T : value class
    public ref struct Reinterpret
    {
        private:
        const static int size = sizeof(T);
    
        public:    
        static int AsInt(T t)
        {
            return *((Int32*) (void*) (&t));
        }
    }
    

    This will then let you write:

    static void IsSet<T>(T value, T flags) where T : struct
    {
        if (!typeof(T).IsEnum)
            throw new InvalidOperationException(typeof(T).Name +" is not an enum!");
        Type t = Enum.GetUnderlyingType(typeof(T));
        if (t == typeof(int))
        {
             return (Reinterpret.AsInt(value) & Reinterpret.AsInt(flags)) != 0
        }
        else if (t == typeof(byte))
        {
             return (Reinterpret.AsByte(value) & Reinterpret.AsByte(flags)) != 0
        }
        // you get the idea...        
    }
    

    You cannot constrain to enums. But the mathematical validity of these methods do not change if they are used with non enum types so you could allow them if you can determine that they are convertible to a struct of the relevant size.

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