check if an enum has any flags in common [duplicate]
Asked Answered
D

3

8

Consider I have this extension method:

public static bool HasAnyFlagInCommon(this System.Enum type, Enum value)
{
    var flags = value.ToString().Split(new string[] { ", " }, 
                                    StringSplitOptions.None);
    foreach (var flag in flags)
    {
        if (type.ToString() == flag)
            return true;
    }
    return false;
}

And the following situation:

[Flags]
enum Bla
{
    A = 0,
    B = 1,
    C = 2,
    D = 4
}

Bla foo = Bla.A | Bla.B;
Bla bar = Bla.A;

bar.HasAnyFlagInCommon(foo); //returns true

I want to check if foo has any flags in common with bar, but there got to be a better way of achiving this behavior in the extension method.

I also tried like this, but is always returns true:

    public static bool HasAnyFlagInCommon(this System.Enum type, Enum value)
    {
        var flags = Enum.GetValues(value.GetType()).Cast<Enum>()
                                 .Where(item => value.HasFlag(item));
        foreach (var flag in flags)
        {
            if (type == flag)
                return true;
        }
        return false;
    }
Drover answered 13/12, 2012 at 18:38 Comment(0)
T
4

Something like

public static bool HasAnyFlagInCommon(this System.Enum type, Enum value)
{
    return (((long)type) & ((long)value)) != 0;
}

The & gives 1 for any bit that is set in both enums, so if there are any such bits the result is non-zero.

(I've used long in the hope it will work for whatever type underlies the enum; int should be fine in your case.)

Tamratamsky answered 13/12, 2012 at 19:55 Comment(2)
This answer is incorrect. It does not compile.Boon
@Kit: This should compile just fine if it's declared in a static class (as all extension methods must be).Gazebo
G
7

You can simply cast the Enum value to a ulong (to account for the possibility that the underlying type is not the default of int). If the result != 0, at least one flag was set.

ulong theValue = (ulong)value;
return (theValue != 0);

Remember, at the end of the day, the enum is backed by one of byte, sbyte, short, ushort, int, uint, long, or ulong.

http://msdn.microsoft.com/en-us/library/sbbt4032.aspx

A flag being set is the same as a corresponding bit being turned on in the backing type. The ulong above will only be 0 if all bits are turned off.

UPDATE

The question was edited after this answer was posted, so here's a modification to account for that update:

To then see whether the enum has any flags in common with another instance of that enum, you can use bitwise and. If both have any common bit position set, the result will be non-zero:

var anyFlagsInCommon = ((ulong)value) & ((ulong)compareTo);
Gazebo answered 13/12, 2012 at 18:41 Comment(2)
I think you got the wrong idea, I edited my question to clear things up. Still using the underlying number could be a solution.Drover
Also, even if this was "are any defined flags set", it wouldn't return the right result if a bit had been set somehow what wasn't one of the defined flags.Tamratamsky
T
4

Something like

public static bool HasAnyFlagInCommon(this System.Enum type, Enum value)
{
    return (((long)type) & ((long)value)) != 0;
}

The & gives 1 for any bit that is set in both enums, so if there are any such bits the result is non-zero.

(I've used long in the hope it will work for whatever type underlies the enum; int should be fine in your case.)

Tamratamsky answered 13/12, 2012 at 19:55 Comment(2)
This answer is incorrect. It does not compile.Boon
@Kit: This should compile just fine if it's declared in a static class (as all extension methods must be).Gazebo
R
1

We have an extension method based on the Has() extension method described in this website: http://somewebguy.wordpress.com/2010/02/23/enumeration-extensions-2. It should be faster than converting to string, but I haven't checked the performance. The relavent subset is:

    /// <summary>
    /// Checks if an enumerated type contains a value
    /// </summary>
    public static bool Has<T>(this Enum value, T check) {
        Type type = value.GetType();

        //determine the values
        object result = value;
        _Value parsed = new _Value(check, type);
        if (parsed.Signed is long) {
            return (Convert.ToInt64(value)& (long)parsed.Signed) == (long)parsed.Signed;
        }
        else if (parsed.Unsigned is ulong) {
            return (Convert.ToUInt64(value) & (ulong)parsed.Unsigned) == (ulong)parsed.Unsigned;
        }
        else {
            return false;
        }
    }

    //class to simplfy narrowing values between 
    //a ulong and long since either value should
    //cover any lesser value
    private class _Value {

        //cached comparisons for tye to use
        private static Type _UInt64 = typeof(ulong);
        private static Type _UInt32 = typeof(long);

        public long? Signed;
        public ulong? Unsigned;

        public _Value(object value, Type type) {

            //make sure it is even an enum to work with
            if (!type.IsEnum) {
                throw new ArgumentException("Value provided is not an enumerated type!");
            }

            //then check for the enumerated value
            Type compare = Enum.GetUnderlyingType(type);

            //if this is an unsigned long then the only
            //value that can hold it would be a ulong
            if (compare.Equals(_Value._UInt32) || compare.Equals(_Value._UInt64)) {
                this.Unsigned = Convert.ToUInt64(value);
            }
            //otherwise, a long should cover anything else
            else {
                this.Signed = Convert.ToInt64(value);
            }

        }
    }
Ragout answered 7/9, 2020 at 15:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.