Invert overflow flags

Suppose I have the following flags:

[Flags]
public enum Foo
{
    None = 0,
    Foo1 = 1,
    Foo2 = 2,
    Foo4 = 4,
    Foo8 = 8
}

      

Now I have a variable foo:

var foo = Foo.Foo1 | Foo.Foo4;

      

I want to get the following inverted flags foo

. It would mean something like this:

Foo.Foo2 | Foo.Foo8

      

I tried the ~ operator. But since my enum is an int32 value, it inverts all 32 bits. But I would just need to invert the bits used by mine Foo enum

.

EDIT: Foo1 | Foo4 will be equal to the following bitmask:

00000000 00000000 00000000 00000101

      

If you invert this bit mask with the ~ operator, you get the following result:

11111111 11111111 11111111 11111010

      

As a result, I would like:

00000000 00000000 00000000 00001010

      

As you can see. I just would like to invert the bit USED by enumerating Foo. Not all bits are only a 32-integer value.

+3


source to share


2 answers


What you want to do is concatenate all the enum values ​​and then mask it with the complement of the current value.

        Foo value = Foo.Foo4;
        Foo allValues = (Foo)0;
        foreach (var v in Enum.GetValues(typeof(Foo)))
            allValues |= (Foo)v;
        var compliment = allValues & ~(value);

      

Or you can combine values ​​with Linq and cache them statically for performance:

    public static class FooHelper
    {
        private readonly static Foo allValues = ((Foo[])Enum.GetValues(typeof(Foo))).Aggregate((Foo)0, (all, cur) => all | cur);

        public static Foo AllValues { get { return allValues ; } }
    }

      

And than:

        var foo = Foo.Foo1 | Foo.Foo4;
        var compliment = FooHelper.AllValues & ~(foo);

      



Refresh

If you want a common method to concatenate all of the enum flag values, you can do this:

var compliment = EnumHelper.GetAll<Foo>() & ~(value);

      

where the underlying enum data is cached in a lazy parameterized singleton instance:

/// <summary>
/// Contains generic utilities for enums, constrained for enums only.
/// </summary>
public sealed class EnumHelper : Enums<Enum>
{
    private EnumHelper()
    {
    }
}

/// <summary>
/// For use by EnumHelper, not for direct use.
/// </summary>
public abstract class Enums<TEnumBase> where TEnumBase : class, IConvertible
{
    // Generic singleton remembering basic properties about specified enums, cached for performance.
    sealed class DataSingleton<TEnum> where TEnum : struct, TEnumBase
    {
        static readonly DataSingleton<TEnum> instance = new DataSingleton<TEnum>();

        readonly bool isSigned;
        readonly TEnum allValues;
        readonly bool hasFlags;

        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static DataSingleton()
        {
        }

        DataSingleton()
        {
            isSigned = GetIsSigned();
            allValues = GetAll();
            hasFlags = GetHasFlags();
        }

        static bool GetHasFlags()
        {
            var attributes = typeof(TEnum).GetCustomAttributes(typeof(FlagsAttribute), false);
            return attributes != null && attributes.Length > 0;
        }

        static bool GetIsSigned()
        {
            var underlyingType = Enum.GetUnderlyingType(typeof(TEnum));
            bool isSigned = (underlyingType == typeof(long) || underlyingType == typeof(int) || underlyingType == typeof(short) || underlyingType == typeof(sbyte));
            bool isUnsigned = (underlyingType == typeof(ulong) || underlyingType == typeof(uint) || underlyingType == typeof(ushort) || underlyingType == typeof(byte));
            if (!isSigned && !isUnsigned)
                throw new InvalidOperationException();
            return isSigned;
        }

        static TEnum GetAll()
        {
            if (GetIsSigned())
            {
                long value = 0;
                foreach (var v in Enum.GetValues(typeof(TEnum)))
                    // Not sure I need the culture but Microsoft passes it in Enum.ToUInt64(Object value) - http://referencesource.microsoft.com/#mscorlib/system/enum.cs
                    value |= Convert.ToInt64(v, CultureInfo.InvariantCulture);
                return (TEnum)Enum.ToObject(typeof(TEnum), value);
            }
            else
            {
                ulong value = 0;
                foreach (var v in Enum.GetValues(typeof(TEnum)))
                    // Not sure I need the culture but Microsoft passes it in Enum.ToUInt64(Object value) - http://referencesource.microsoft.com/#mscorlib/system/enum.cs
                    value |= Convert.ToUInt64(v, CultureInfo.InvariantCulture);
                return (TEnum)Enum.ToObject(typeof(TEnum), value);
            }
        }

        public bool HasFlags { get { return hasFlags; } }

        public bool IsSigned { get { return isSigned; } }

        public TEnum AllValues { get { return allValues; } }

        public static DataSingleton<TEnum> Instance { get { return instance; } }
    }

    private static void ThrowOnEnumWithoutFlags<TEnum>(DataSingleton<TEnum> data) where TEnum : struct, TEnumBase
    {
        if (!data.HasFlags)
        {
            throw (new ArgumentException("The generic argument [<TEnum>] must be an enumeration with the [FlagsAttribute] applied.", "TEnum: " + typeof(TEnum).FullName));
        }
    }

    public static TEnum GetAll<TEnum>() where TEnum : struct, TEnumBase
    {
        var data = DataSingleton<TEnum>.Instance;
        ThrowOnEnumWithoutFlags<TEnum>(data);
        return data.AllValues;
    }
}

      

+6


source


To invert a single Enum flag try this



private Foo foos; 
private static void FlagInvert(Foo foo)
    {var res = foos.HasFlag(foo) ? foos &= ~foo : foos  |= foo;}

      

0


source







All Articles